Enable authentication options in a web app by using Azure AD B2C
This article describes how to enable, customize, and enhance the Azure Active Directory B2C (Azure AD B2C) authentication experience for your web application.
Before you start, it's important to familiarize yourself with the following articles:
Use a custom domain
By using a custom domain, you can fully brand the authentication URL. From a user perspective, users remain on your domain during the authentication process, rather than being redirected to the Azure AD B2C b2clogin.com domain name.
To remove all references to "b2c" in the URL, you can also replace your B2C tenant name, contoso.onmicrosoft.com, in the authentication request URL with your tenant ID GUID. For example, you can change https://fabrikamb2c.b2clogin.com/contoso.onmicrosoft.com/
to https://account.contosobank.co.uk/<tenant ID GUID>/
.
To use a custom domain and your tenant ID in the authentication URL, follow the guidance in Enable custom domains. Under the project root folder, open the appsettings.json file. This file contains information about your Azure AD B2C identity provider.
In the appsettings.json file, do the following:
- Update the
Instance
entry with your custom domain. - Update the
Domain
entry with your tenant ID. For more information, see Use tenant ID.
The following JSON shows the app settings before the change:
"AzureAdB2C": {
"Instance": "https://contoso.b2clogin.com",
"Domain": "tenant-name.onmicrosoft.com",
...
}
The following JSON shows the app settings after the change:
"AzureAdB2C": {
"Instance": "https://login.contoso.com",
"Domain": "00000000-0000-0000-0000-000000000000",
...
}
Support advanced scenarios
The AddMicrosoftIdentityWebAppAuthentication
method in the Microsoft identity platform API lets developers add code for advanced authentication scenarios or subscribe to OpenIdConnect events. For example, you can subscribe to OnRedirectToIdentityProvider, which allows you to customize the authentication request your app sends to Azure AD B2C.
To support advanced scenarios, open the Startup.cs file and, in the ConfigureServices
function, replace AddMicrosoftIdentityWebAppAuthentication
with the following code snippet:
// Configuration to sign-in users with Azure AD B2C
//services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C");
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options =>
{
Configuration.Bind("AzureAdB2C", options);
options.Events ??= new OpenIdConnectEvents();
options.Events.OnRedirectToIdentityProvider += OnRedirectToIdentityProviderFunc;
});
The preceding code adds the OnRedirectToIdentityProvider event with a reference to the OnRedirectToIdentityProviderFunc
method. Add the following code snippet to the Startup.cs
class.
private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
// Custom code here
// Don't remove this line
await Task.CompletedTask.ConfigureAwait(false);
}
You can pass parameters between your controller and the OnRedirectToIdentityProvider
function by using context parameters.
Prepopulate the sign-in name
During a sign-in user journey, your app might target a specific user. When an app targets a user, it can specify in the authorization request the login_hint
query parameter with the user's sign-in name. Azure AD B2C automatically populates the sign-in name, and the user needs to provide only the password.
To prepopulate the sign-in name, do the following:
If you're using a custom policy, add the required input claim, as described in Set up direct sign-in.
Complete the Support advanced scenarios procedure.
Add the following line of code to the
OnRedirectToIdentityProvider
function:private async Task OnRedirectToIdentityProviderFunc(RedirectContext context) { context.ProtocolMessage.LoginHint = "emily@contoso.com"; // More code await Task.CompletedTask.ConfigureAwait(false); }
Preselect an identity provider
If you configured the sign-in journey for your application to include social accounts, such as Facebook, LinkedIn, or Google, you can specify the domain_hint
parameter. This query parameter provides a hint to Azure AD B2C about the social identity provider that should be used for sign-in. For example, if the application specifies domain_hint=facebook.com
, the sign-in flow goes directly to the Facebook sign-in page.
To redirect users to an external identity provider, do the following:
Check the domain name of your external identity provider. For more information, see Redirect sign-in to a social provider.
Complete the Support advanced scenarios procedure.
In the
OnRedirectToIdentityProviderFunc
function, add the following line of code to theOnRedirectToIdentityProvider
function:private async Task OnRedirectToIdentityProviderFunc(RedirectContext context) { context.ProtocolMessage.DomainHint = "facebook.com"; // More code await Task.CompletedTask.ConfigureAwait(false); }
Specify the UI language
Language customization in Azure AD B2C allows your user flow to accommodate a variety of languages to suit your customers' needs. For more information, see Language customization.
To set the preferred language, do the following:
Complete the Support advanced scenarios procedure.
Add the following line of code to the
OnRedirectToIdentityProvider
function:private async Task OnRedirectToIdentityProviderFunc(RedirectContext context) { context.ProtocolMessage.UiLocales = "es"; // More code await Task.CompletedTask.ConfigureAwait(false); }
Pass a custom query string parameter
With custom policies, you can pass a custom query string parameter. A good use-case example is when you want to dynamically change the page content.
To pass a custom query string parameter, do the following:
Configure the ContentDefinitionParameters element.
Complete the Support advanced scenarios procedure.
Add the following line of code to the
OnRedirectToIdentityProvider
function:private async Task OnRedirectToIdentityProviderFunc(RedirectContext context) { context.ProtocolMessage.Parameters.Add("campaignId", "123"); // More code await Task.CompletedTask.ConfigureAwait(false); }
Pass an ID token hint
A relying party application can send an inbound JSON Web Token (JWT) as part of the OAuth2 authorization request. The inbound token is a hint about the user or the authorization request. Azure AD B2C validates the token and then extracts the claim.
To include an ID token hint in the authentication request, do the following:
Complete the Support advanced scenarios procedure.
In your custom policy, define an ID token hint technical profile.
Add the following line of code to the
OnRedirectToIdentityProvider
function:private async Task OnRedirectToIdentityProviderFunc(RedirectContext context) { // The idTokenHint variable holds your ID token context.ProtocolMessage.IdTokenHint = idTokenHint // More code await Task.CompletedTask.ConfigureAwait(false); }
Account controller
If you want to customize the SignIn, SignUp, or SignOut actions, we encourage you to create your own controller. Having your own controller allows you to pass parameters between your controller and the authentication library. AccountController
is part of Microsoft.Identity.Web.UI
NuGet package, which handles the sign-in and sign-out actions. You can find its implementation in the Microsoft Identity Web library.
Add the Account controller
In your Visual Studio project, right-click the Controllers folder, and then add a new Controller. Select MVC - Empty Controller, and then provide the name MyAccountController.cs.
The following code snippet demonstrates a custom MyAccountController
with the SignIn action.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace mywebapp.Controllers
{
[AllowAnonymous]
[Area("MicrosoftIdentity")]
[Route("[area]/[controller]/[action]")]
public class MyAccountController : Controller
{
[HttpGet("{scheme?}")]
public IActionResult SignIn([FromRoute] string scheme)
{
scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
return Challenge(properties, scheme);
}
}
}
In the _LoginPartial.cshtml view, change the sign-in link to your controller.
<form method="get" asp-area="MicrosoftIdentity" asp-controller="MyAccount" asp-action="SignIn">
Pass the Azure AD B2C policy ID
The following code snippet demonstrates a custom MyAccountController
with the SignIn and SignUp action. The action passes a parameter named policy
to the authentication library. This allows you to provide the correct Azure AD B2C policy ID for the specific action.
public IActionResult SignIn([FromRoute] string scheme)
{
scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
properties.Items["policy"] = "B2C_1_SignIn";
return Challenge(properties, scheme);
}
public IActionResult SignUp([FromRoute] string scheme)
{
scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
properties.Items["policy"] = "B2C_1_SignUp";
return Challenge(properties, scheme);
}
In the _LoginPartial.cshtml view, change the asp-controller
value to MyAccountController
for any other authentication links, such as sign-up or edit profile.
Pass custom parameters
The following code snippet demonstrates a custom MyAccountController
with the SignIn action. The action passes a parameter named campaign_id
to the authentication library.
public IActionResult SignIn([FromRoute] string scheme)
{
scheme ??= OpenIdConnectDefaults.AuthenticationScheme;
var redirectUrl = Url.Content("~/");
var properties = new AuthenticationProperties { RedirectUri = redirectUrl };
properties.Items["policy"] = "B2C_1_SignIn";
properties.Items["campaign_id"] = "1234";
return Challenge(properties, scheme);
}
Complete the Support advanced scenarios procedure and then, in the OnRedirectToIdentityProvider
method, read the custom parameter:
private async Task OnRedirectToIdentityProviderFunc(RedirectContext context)
{
// Read the custom parameter
var campaign_id = context.Properties.Items.FirstOrDefault(x => x.Key == "campaign_id").Value;
// Add your custom code here
if (campaign_id != null)
{
// Send parameter to authentication request
context.ProtocolMessage.SetParameter("campaign_id", campaign_id);
}
await Task.CompletedTask.ConfigureAwait(false);
}
Secure your logout redirect
After logout, the user is redirected to the URI specified in the post_logout_redirect_uri
parameter, regardless of the reply URLs that have been specified for the application. However, if a valid id_token_hint
is passed and the Require ID Token in logout requests is turned on, Azure AD B2C verifies that the value of post_logout_redirect_uri
matches one of the application's configured redirect URIs before performing the redirect. If no matching reply URL was configured for the application, an error message is displayed and the user is not redirected.
To support a secured logout redirect in your application, first follow the steps in the Account controller and Support advanced scenarios sections. Then follow the steps below:
In
MyAccountController.cs
controller, add a SignOut action using the following code snippet:[HttpGet("{scheme?}")] public async Task<IActionResult> SignOutAsync([FromRoute] string scheme) { scheme ??= OpenIdConnectDefaults.AuthenticationScheme; //obtain the id_token var idToken = await HttpContext.GetTokenAsync("id_token"); //send the id_token value to the authentication middleware properties.Items["id_token_hint"] = idToken; return SignOut(properties,CookieAuthenticationDefaults.AuthenticationScheme,scheme); }
In the Startup.cs class, parse the
id_token_hint
value and append the value to the authentication request. The following code snippet demonstrates how to pass theid_token_hint
value to the authentication request:private async Task OnRedirectToIdentityProviderForSignOutFunc(RedirectContext context) { var id_token_hint = context.Properties.Items.FirstOrDefault(x => x.Key == "id_token_hint").Value; if (id_token_hint != null) { // Send parameter to authentication request context.ProtocolMessage.SetParameter("id_token_hint", id_token_hint); } await Task.CompletedTask.ConfigureAwait(false); }
In the
ConfigureServices
function, add theSaveTokens
option for Controllers have access to theid_token
value:services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(options => { Configuration.Bind("AzureAdB2C", options); options.Events ??= new OpenIdConnectEvents(); options.Events.OnRedirectToIdentityProviderForSignOut += OnRedirectToIdentityProviderForSignOutFunc; options.SaveTokens = true; });
In the appsettings.json configuration file, add your logout redirect URI path to
SignedOutCallbackPath
key."AzureAdB2C": { "Instance": "https://<your-tenant-name>.b2clogin.com", "ClientId": "<web-app-application-id>", "Domain": "<your-b2c-domain>", "SignedOutCallbackPath": "/signout/<your-sign-up-in-policy>", "SignUpSignInPolicyId": "<your-sign-up-in-policy>" }
In the above example, the post_logout_redirect_uri passed into the logout request will be in the format: https://your-app.com/signout/<your-sign-up-in-policy>
. This URL must be added to the Application Registration's reply URL's.
Role-based access control
With authorization in ASP.NET Core you can check to see whether users are authorized to access a protected resource by using one of the following methods:
In the ConfigureServices
method, add the AddAuthorization
method, which adds the authorization model. The following example creates a policy named EmployeeOnly
. The policy checks to verify that a claim EmployeeNumber
exists. The value of the claim must be one of the following IDs: 1, 2, 3, 4, or 5.
services.AddAuthorization(options =>
{
options.AddPolicy("EmployeeOnly", policy =>
policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
});
You control authorization in ASP.NET Core by using AuthorizeAttribute and its various parameters. In its most basic form, applying the Authorize
attribute to a controller, action, or Razor Page limits access to that component's authenticated users.
You apply policies to controllers by using the Authorize
attribute with the policy name. The following code limits access to the Claims
action to users who are authorized by the EmployeeOnly
policy:
[Authorize(Policy = "EmployeeOnly")]
public IActionResult Claims()
{
return View();
}
Next steps
- To learn more about authorization, see Introduction to authorization in ASP.NET Core.