Azure AD B2C - Role management
I have an Asp.NET MVC Application connected with Azure AD B2C.
In the Administrator settings I've created an Administrators Group:
In my code I would like to use [Authorize(Roles = "Administrator")]
With regular Azure Active Directory it was easy to add (just 3 lines of code). But for the Azure AD B2C I cannot find any tutorial or example in the web which is working. Maybe you can tell me what i need to modify.
Here is the ConfigureAuth method of my Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// Generate the metadata address using the tenant and policy information
MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = ClientId,
RedirectUri = RedirectUri,
PostLogoutRedirectUri = RedirectUri,
// Specify the callbacks for each type of notifications
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed,
},
// Specify the claims to validate
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name"
},
// Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}"
}
);
}
Solution 1:
Azure AD B2C does not yet include Group claims in the token it sends to the application thus you can't follow the same approach as you outlined with Azure AD (which does include group claims in the token).
You can support this feature ask by voting for it in the Azure AD B2C feedback forum: Get user membership groups in the claims with Azure AD B2C
That being said, you can do some extra work in this application to have it manually retrieve these claims the group claims and inject them into the token.
First, register a separate application that'll call the Microsoft Graph to retrieve the group claims.
- Go to https://apps.dev.microsoft.com
- Create an app with Application Permissions : Directory.Read.All.
- Add an application secret by clicking on Generate new password
- Add a Platform and select Web and give it any redirect URI, (e.g.
https://yourtenant.onmicrosoft.com/groups
) - Consent to this application by navigating to:
https://login.microsoftonline.com/YOUR_TENANT.onmicrosoft.com/adminconsent?client_id=YOUR_CLIENT_ID&state=12345&redirect_uri=YOUR_REDIRECT_URI
Then, you'll need to add code the following code inside of the OnAuthorizationCodeReceived
handler, right after redeeming the code:
var authority = $"https://login.microsoftonline.com/{Tenant}";
var graphCca = new ConfidentialClientApplication(GraphClientId, authority, GraphRedirectUri, new ClientCredential(GraphClientSecret), userTokenCache, null);
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
try
{
AuthenticationResult authenticationResult = await graphCca.AcquireTokenForClientAsync(scopes);
string token = authenticationResult.AccessToken;
using (var client = new HttpClient())
{
string requestUrl = $"https://graph.microsoft.com/v1.0/users/{signedInUserID}/memberOf?$select=displayName";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
var json = JObject.Parse(responseString);
foreach (var group in json["value"])
notification.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Role, group["displayName"].ToString(), System.Security.Claims.ClaimValueTypes.String, "Graph"));
//TODO: Handle paging.
// https://developer.microsoft.com/en-us/graph/docs/concepts/paging
// If the user is a member of more than 100 groups,
// you'll need to retrieve the next page of results.
}
} catch (Exception ex)
{
//TODO: Handle
throw;
}