Microsoft Entra (ME-ID) groups, Administrator Roles, and App Roles (.NET 5 to .NET 7)
Note
This isn't the latest version of this article. For the current ASP.NET Core release, see the latest version of ASP.NET Core Blazor WebAssembly with Microsoft Entra ID groups and roles.
This article explains how to configure Blazor WebAssembly to use Microsoft Entra ID groups and roles.
Microsoft Entra (ME-ID) provides several authorization approaches that can be combined with ASP.NET Core Identity:
- Groups
- Security
- Microsoft 365
- Distribution
- Roles
- ME-ID Administrator Roles
- App Roles
The guidance in this article applies to the Blazor WebAssembly ME-ID deployment scenarios described in the following articles:
The article's guidance provides instructions for client and server apps:
- CLIENT: Standalone Blazor WebAssembly apps or the Client app of a hosted Blazor solution.
- SERVER: ASP.NET Core server API/web API apps or the Server app of a hosted Blazor solution. You can ignore the SERVER guidance throughout the article for a standalone Blazor WebAssembly app.
The examples in this article take advantage of new .NET/C# features. When using the examples with .NET 7 or earlier, minor modifications are required. However, the text and code examples that pertain to interacting with ME-ID and Microsoft Graph are the same for all versions of ASP.NET Core.
Prerequisite
The guidance in this article implements the Microsoft Graph API per the Graph SDK guidance in Use Graph API with ASP.NET Core Blazor WebAssembly. Follow the Graph SDK implementation guidance to configure the app and test it to confirm that the app can obtain Graph API data for a test user account. Additionally, see the Graph API article's security article cross-links to review Microsoft Graph security concepts.
When testing with the Graph SDK locally, we recommend using a new in-private/incognito browser session for each test to prevent lingering cookies from interfering with tests. For more information, see Secure an ASP.NET Core Blazor WebAssembly standalone app with Microsoft Entra ID.
Scopes
To permit Microsoft Graph API calls for user profile, role assignment, and group membership data:
- A CLIENT app is configured with the delegated
User.Read
scope (https://graph.microsoft.com/User.Read
) in the Azure portal because access to read user data is determined by the scopes granted (delegated) to individual users. - A SERVER app is configured with the application
GroupMember.Read.All
scope (https://graph.microsoft.com/GroupMember.Read.All
) in the Azure portal because access is for the app to obtain information about group membership, not based on individual user authorization to access data about group members.
The preceding scopes are required in addition to the scopes required in ME-ID deployment scenarios described by the articles listed earlier (Standalone with Microsoft Accounts, Standalone with ME-ID, and Hosted with ME-ID).
For more information, see Overview of permissions and consent in the Microsoft identity platform and Overview of Microsoft Graph permissions.
Permissions and scopes mean the same thing and are used interchangeably in security documentation and the Azure portal. Unless the text is referring to the Azure portal, this article uses scope/scopes when referring to Graph permissions.
Scopes are case insensitive, so User.Read
is the same as user.read
. Feel free to use either format, but we recommend a consistent choice across application code.
Group Membership Claims attribute
In the app's manifest in the Azure portal for CLIENT and SERVER apps, set the groupMembershipClaims
attribute to DirectoryRole
. A value of DirectoryRole
results in ME-ID sending all of the roles of the signed-in user in the well-known IDs claim (wids
):
- Open the app's Azure portal registration.
- Select Manage > Manifest in the sidebar.
- Find the
groupMembershipClaims
attribute. - Set the value to
DirectoryRole
("groupMembershipClaims": "DirectoryRole"
). - Select the Save button if you made changes.
In the app's manifest in the Azure portal for CLIENT and SERVER apps, set the groupMembershipClaims
attribute to All
. A value of All
results in ME-ID sending all of the security groups, distribution groups, and roles of the signed-in user in the well-known IDs claim (wids
):
- Open the app's Azure portal registration.
- Select Manage > Manifest in the sidebar.
- Find the
groupMembershipClaims
attribute. - Set the value to
All
("groupMembershipClaims": "All"
). - Select the Save button if you made changes.
Custom user account
Assign users to ME-ID security groups and ME-ID Administrator Roles in the Azure portal.
The examples in this article:
- Assume that a user is assigned to the ME-ID Billing Administrator role in the Azure portal ME-ID tenant for authorization to access server API data.
- Use authorization policies to control access within the CLIENT and SERVER apps.
In the CLIENT app, extend RemoteUserAccount to include properties for:
Roles
: ME-ID App Roles array (covered in the App Roles section)Wids
: ME-ID Administrator Roles in well-known IDs claim (wids
)Oid
: Immutable object identifier claim (oid
) (uniquely identifies a user within and across tenants)
CustomUserAccount.cs
:
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
namespace BlazorSample;
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("roles")]
public List<string>? Roles { get; set; }
[JsonPropertyName("wids")]
public List<string>? Wids { get; set; }
[JsonPropertyName("oid")]
public string? Oid { get; set; }
}
Add a package reference to the CLIENT app for Microsoft.Graph
.
Note
For guidance on adding packages to .NET apps, see the articles under Install and manage packages at Package consumption workflow (NuGet documentation). Confirm correct package versions at NuGet.org.
Add the Graph SDK utility classes and configuration in the Graph SDK guidance of the Use Graph API with ASP.NET Core Blazor WebAssembly article. Specify the User.Read
scope for the access token as the article shows in its example wwwroot/appsettings.json
file.
Add the following custom user account factory to the CLIENT app. The custom user factory is used to establish:
- App Role claims (
appRole
) (covered in the App Roles section). - ME-ID Administrator Role claims (
directoryRole
). - Example user profile data claims for the user's mobile phone number (
mobilePhone
) and office location (officeLocation
). - ME-ID Group claims (
directoryGroup
). - An ILogger (
logger
) for convenience in case you wish to log information or errors.
CustomAccountFactory.cs
:
using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions.Authentication;
namespace BlazorSample;
public class CustomAccountFactory()
: AccountClaimsPrincipalFactory<CustomUserAccount>
{
private readonly ILogger<CustomAccountFactory> logger;
private readonly IServiceProvider serviceProvider;
private readonly string? baseUrl =
string.Join("/",
config.GetSection("MicrosoftGraph")["BaseUrl"] ??
"https://graph.microsoft.com",
config.GetSection("MicrosoftGraph")["Version"] ??
"v1.0");
public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
IServiceProvider serviceProvider,
ILogger<CustomAccountFactory> logger)
: base(accessor)
{
this.serviceProvider = serviceProvider;
this.logger = logger;
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account,
RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity is not null &&
initialUser.Identity.IsAuthenticated)
{
var userIdentity = initialUser.Identity as ClaimsIdentity;
if (userIdentity is not null && !string.IsNullOrEmpty(baseUrl))
{
account?.Roles?.ForEach((role) =>
{
userIdentity.AddClaim(new Claim("appRole", role));
});
account?.Wids?.ForEach((wid) =>
{
userIdentity.AddClaim(new Claim("directoryRole", wid));
});
try
{
var client = new GraphServiceClient(
new HttpClient(),
serviceProvider
.GetRequiredService<IAuthenticationProvider>(),
baseUrl);
var user = await client.Me.GetAsync();
if (user is not null)
{
userIdentity.AddClaim(new Claim("mobilephone",
user.MobilePhone ?? "(000) 000-0000"));
userIdentity.AddClaim(new Claim("officelocation",
user.OfficeLocation ?? "Not set"));
}
var requestMemberOf = client.Users[account?.Oid].MemberOf;
var graphGroups = await requestMemberOf.GraphGroup.GetAsync();
if (graphGroups?.Value is not null)
{
foreach (var entry in graphGroups.Value)
{
if (entry.Id is not null)
{
userIdentity.AddClaim(
new Claim("directoryGroup", entry.Id));
}
}
}
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
return initialUser;
}
}
using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;
namespace BlazorSample;
public class CustomAccountFactory()
: AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
private readonly ILogger<CustomAccountFactory> logger;
private readonly IServiceProvider serviceProvider;
public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
IServiceProvider serviceProvider,
ILogger<CustomAccountFactory> logger)
: base(accessor)
{
this.serviceProvider = serviceProvider;
this.logger = logger;
}
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account,
RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity is not null &&
initialUser.Identity.IsAuthenticated)
{
var userIdentity = initialUser.Identity as ClaimsIdentity;
if (userIdentity is not null)
{
account?.Roles?.ForEach((role) =>
{
userIdentity.AddClaim(new Claim("appRole", role));
});
account?.Wids?.ForEach((wid) =>
{
userIdentity.AddClaim(new Claim("directoryRole", wid));
});
try
{
var client = ActivatorUtilities
.CreateInstance<GraphServiceClient>(serviceProvider);
var request = client.Me.Request();
var user = await request.GetAsync();
if (user is not null)
{
userIdentity.AddClaim(new Claim("mobilephone",
user.MobilePhone ?? "(000) 000-0000"));
userIdentity.AddClaim(new Claim("officelocation",
user.OfficeLocation ?? "Not set"));
}
var requestMemberOf = client.Users[account?.Oid].MemberOf;
var memberships = await requestMemberOf.Request().GetAsync();
if (memberships is not null)
{
foreach (var entry in memberships)
{
if (entry.ODataType == "#microsoft.graph.group")
{
userIdentity.AddClaim(
new Claim("directoryGroup", entry.Id));
}
}
}
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
return initialUser;
}
}
The preceding code doesn't include transitive memberships. If the app requires direct and transitive group membership claims, replace the MemberOf
property (IUserMemberOfCollectionWithReferencesRequestBuilder
) with TransitiveMemberOf
(IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder
).
The preceding code ignores group membership claims (groups
) that are ME-ID Administrator Roles (#microsoft.graph.directoryRole
type) because the GUID values returned by ME-ID are Administrator Role entity IDs and not role Template IDs. Entity IDs aren't stable across tenants and shouldn't be used to create authorization policies for users in apps. Always use Template IDs for ME-ID Administrator Roles provided by wids
claims.
The wids
claim (and thus directoryRole
claim) with a value of b79fbf4d-3ef9-4689-8143-76b194e85509
exists for non-guest accounts of the tenant. It doesn't refer to an ME-ID Administrator Role Template ID.
In the CLIENT app, configure the MSAL authentication to use the custom user account factory.
Confirm that the Program
file uses the Microsoft.AspNetCore.Components.WebAssembly.Authentication namespace:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
Update the AddMsalAuthentication call to the following. Note that the Blazor framework's RemoteUserAccount is replaced by the app's CustomUserAccount
for the MSAL authentication and account claims principal factory:
builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
CustomUserAccount>(options =>
{
builder.Configuration.Bind("AzureAd",
options.ProviderOptions.Authentication);
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
CustomAccountFactory>();
Confirm the presence of the Graph SDK code described by the Use Graph API with ASP.NET Core Blazor WebAssembly article and that the wwwroot/appsettings.json
configuration is correct per the Graph SDK guidance:
var baseUrl =
string.Join("/",
builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
"https://graph.microsoft.com",
builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
"v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
.Get<List<string>>() ?? [ "user.read" ];
builder.Services.AddGraphClient(baseUrl, scopes);
wwwroot/appsettings.json
:
{
"MicrosoftGraph": {
"BaseUrl": "https://graph.microsoft.com",
"Version": "v1.0",
"Scopes": [
"user.read"
]
}
}
Authorization configuration
In the CLIENT app, create a policy for each App Role, ME-ID Administrator Role, or security group in the Program
file. The following example creates a policy for the ME-ID built-in Billing Administrator role:
builder.Services.AddAuthorizationCore(options =>
{
options.AddPolicy("BillingAdministrator", policy =>
policy.RequireClaim("directoryRole",
"b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});
For the complete list of IDs for ME-ID Administrator Roles, see Role template IDs in the Entra documentation. For more information on authorization policies, see Policy-based authorization in ASP.NET Core.
In the following examples, the CLIENT app uses the preceding policy to authorize the user.
The AuthorizeView
component works with the policy:
<AuthorizeView Policy="BillingAdministrator">
<Authorized>
<p>
The user is in the 'Billing Administrator' ME-ID Administrator Role
and can see this content.
</p>
</Authorized>
<NotAuthorized>
<p>
The user is NOT in the 'Billing Administrator' role and sees this
content.
</p>
</NotAuthorized>
</AuthorizeView>
Access to an entire component can be based on the policy using an [Authorize]
attribute directive (AuthorizeAttribute):
@page "/"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "BillingAdministrator")]
If the user isn't authorized, they're redirected to the ME-ID sign-in page.
A policy check can also be performed in code with procedural logic.
CheckPolicy.razor
:
@page "/checkpolicy"
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<h1>Check Policy</h1>
<p>This component checks a policy in code.</p>
<button @onclick="CheckPolicy">Check 'BillingAdministrator' policy</button>
<p>Policy Message: @policyMessage</p>
@code {
private string policyMessage = "Check hasn't been made yet.";
[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }
private async Task CheckPolicy()
{
var user = (await authenticationStateTask).User;
if ((await AuthorizationService.AuthorizeAsync(user,
"BillingAdministrator")).Succeeded)
{
policyMessage = "Yes! The 'BillingAdministrator' policy is met.";
}
else
{
policyMessage = "No! 'BillingAdministrator' policy is NOT met.";
}
}
}
Using the preceding approaches, you can also create policy-based access for app roles, where the GUID used for the policy is set in the appRoles
element of the app's manifest in the Azure portal, and security groups, where the GUID used for the policy matches the group Object Id in the Azure portal Groups pane.
Authorize server API/web API access
A SERVER API app can authorize users to access secure API endpoints with authorization policies for security groups, ME-ID Administrator Roles, and App Roles when an access token contains groups
, wids
, and role
claims. The following example creates a policy for the ME-ID Billing Administrator role in the Program
file using the wids
(well-known IDs/Role Template IDs) claims:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("BillingAdministrator", policy =>
policy.RequireClaim("wids", "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});
For the complete list of IDs for ME-ID Administrator Roles, see Role template IDs in the Azure documentation. For more information on authorization policies, see Policy-based authorization in ASP.NET Core.
Access to a controller in the SERVER app can be based on using an [Authorize]
attribute with the name of the policy (API documentation: AuthorizeAttribute).
The following example limits access to billing data from the BillingDataController
to Azure Billing Administrators with a policy name of BillingAdministrator
:
using Microsoft.AspNetCore.Authorization;
[Authorize(Policy = "BillingAdministrator")]
[ApiController]
[Route("[controller]")]
public class BillingDataController : ControllerBase
{
...
}
For more information, see Policy-based authorization in ASP.NET Core.
App Roles
To configure the app in the Azure portal to provide App Roles membership claims, see Add app roles to your application and receive them in the token in the Entra documentation.
The following example assumes that the CLIENT and SERVER apps are configured with two roles, and the roles are assigned to a test user:
Admin
Developer
Note
When developing a hosted Blazor WebAssembly app or a client-server pair of standalone apps (a standalone Blazor WebAssembly app and an ASP.NET Core server API/web API app), the appRoles
manifest property of both the client and the server Azure portal app registrations must include the same configured roles. After establishing the roles in the client app's manifest, copy them in their entirety to the server app's manifest. If you don't mirror the manifest appRoles
between the client and server app registrations, role claims aren't established for authenticated users of the server API/web API, even if their access token has the correct entries in the role claims.
Although you can't assign roles to groups without an Microsoft Entra ID Premium account, you can assign roles to users and receive role claims for users with a standard Azure account. The guidance in this section doesn't require an ME-ID Premium account.
When working with the default directory, follow the guidance in Add app roles to your application and receive them in the token to configure and assign roles. If you aren't working with the default directory, edit the app's manifest in the Azure portal to establish the app's roles manually in the appRoles
entry of the manifest file. The following is an example appRoles
entry that creates Admin
and Developer
roles. These example roles are used later in this section's example at the component level to implement access restrictions:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"description": "Administrators manage developers.",
"displayName": "Admin",
"id": "{ADMIN GUID}",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Admin"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Developers write code.",
"displayName": "Developer",
"id": "{DEVELOPER GUID}",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "Developer"
}
],
For the {ADMIN GUID}
and {DEVELOPER GUID}
placeholders in the preceding example, you can generate GUIDs with an online GUID generator (Google search result for "guid generator").
To assign a role to a user (or group if you have a Premium tier Azure account):
- Navigate to Enterprise applications in the ME-ID area of the Azure portal.
- Select the app. Select Manage > Users and groups from the sidebar.
- Select the checkbox for one or more user accounts.
- From the menu above the list of users, select Edit assignment.
- For the Select a role entry, select None selected.
- Choose a role from the list and use the Select button to select it.
- Use the Assign button at the bottom of the screen to assign the role.
Multiple roles are assigned in the Azure portal by re-adding a user for each additional role assignment. Use the Add user/group button at the top of the list of users to re-add a user. Use the preceding steps to assign another role to the user. You can repeat this process as many times as needed to add additional roles to a user (or group).
The CustomAccountFactory
shown in the Custom user account section is set up to act on a role
claim with a JSON array value. Add and register the CustomAccountFactory
in the CLIENT app as shown in the Custom user account section. There's no need to provide code to remove the original role
claim because it's automatically removed by the framework.
In the Program
file of a CLIENT app, specify the claim named "appRole
" as the role claim for ClaimsPrincipal.IsInRole checks:
builder.Services.AddMsalAuthentication(options =>
{
...
options.UserOptions.RoleClaim = "appRole";
});
Note
If you prefer to use the directoryRoles
claim (ADD Administrator Roles), assign "directoryRoles
" to the RemoteAuthenticationUserOptions.RoleClaim.
In the Program
file of a SERVER app, specify the claim named "http://schemas.microsoft.com/ws/2008/06/identity/claims/role
" as the role claim for ClaimsPrincipal.IsInRole checks:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
},
options => { Configuration.Bind("AzureAd", options); });
Note
When a single authentication scheme is registered, the authentication scheme is automatically used as the app's default scheme, and it isn't necessary to state the scheme to AddAuthentication or via AuthenticationOptions. For more information, see Overview of ASP.NET Core Authentication and the ASP.NET Core announcement (aspnet/Announcements #490).
Note
If you prefer to use the wids
claim (ADD Administrator Roles), assign "wids
" to the TokenValidationParameters.RoleClaimType.
After you've completed the preceding steps to create and assign roles to users (or groups if you have a Premium tier Azure account) and implemented the CustomAccountFactory
with the Graph SDK, as explained earlier in this article and in Use Graph API with ASP.NET Core Blazor WebAssembly, you should see an appRole
claim for each assigned role that a signed-in user is assigned (or roles assigned to groups that they are members of). Run the app with a test user to confirm the claim(s) are present as expected. When testing with the Graph SDK locally, we recommend using a new in-private/incognito browser session for each test to prevent lingering cookies from interfering with tests. For more information, see Secure an ASP.NET Core Blazor WebAssembly standalone app with Microsoft Entra ID.
Component authorization approaches are functional at this point. Any of the authorization mechanisms in components of the CLIENT app can use the Admin
role to authorize the user:
-
<AuthorizeView Roles="Admin">
[Authorize]
attribute directive (AuthorizeAttribute)@attribute [Authorize(Roles = "Admin")]
-
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); var user = authState.User; if (user.IsInRole("Admin")) { ... }
Multiple role tests are supported:
Require that the user be in either the
Admin
orDeveloper
role with theAuthorizeView
component:<AuthorizeView Roles="Admin, Developer"> ... </AuthorizeView>
Require that the user be in both the
Admin
andDeveloper
roles with theAuthorizeView
component:<AuthorizeView Roles="Admin"> <AuthorizeView Roles="Developer" Context="innerContext"> ... </AuthorizeView> </AuthorizeView>
For more information on the
Context
for the inner AuthorizeView, see ASP.NET Core Blazor authentication and authorization.Require that the user be in either the
Admin
orDeveloper
role with the[Authorize]
attribute:@attribute [Authorize(Roles = "Admin, Developer")]
Require that the user be in both the
Admin
andDeveloper
roles with the[Authorize]
attribute:@attribute [Authorize(Roles = "Admin")] @attribute [Authorize(Roles = "Developer")]
Require that the user be in either the
Admin
orDeveloper
role with procedural code:@code { private async Task DoSomething() { var authState = await AuthenticationStateProvider .GetAuthenticationStateAsync(); var user = authState.User; if (user.IsInRole("Admin") || user.IsInRole("Developer")) { ... } else { ... } } }
Require that the user be in both the
Admin
andDeveloper
roles with procedural code by changing the conditional OR (||
) to a conditional AND (&&
) in the preceding example:if (user.IsInRole("Admin") && user.IsInRole("Developer"))
Any of the authorization mechanisms in controllers of the SERVER app can use the Admin
role to authorize the user:
[Authorize]
attribute directive (AuthorizeAttribute)[Authorize(Roles = "Admin")]
-
if (User.IsInRole("Admin")) { ... }
Multiple role tests are supported:
Require that the user be in either the
Admin
orDeveloper
role with the[Authorize]
attribute:[Authorize(Roles = "Admin, Developer")]
Require that the user be in both the
Admin
andDeveloper
roles with the[Authorize]
attribute:[Authorize(Roles = "Admin")] [Authorize(Roles = "Developer")]
Require that the user be in either the
Admin
orDeveloper
role with procedural code:static readonly string[] scopeRequiredByApi = new string[] { "API.Access" }; ... [HttpGet] public IEnumerable<ReturnType> Get() { HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi); if (User.IsInRole("Admin") || User.IsInRole("Developer")) { ... } else { ... } return ... }
Require that the user be in both the
Admin
andDeveloper
roles with procedural code by changing the conditional OR (||
) to a conditional AND (&&
) in the preceding example:if (User.IsInRole("Admin") && User.IsInRole("Developer"))
Because .NET string comparisons are case-sensitive, matching role names is also case-sensitive. For example, Admin
(uppercase A
) is not treated as the same role as admin
(lowercase a
).
Pascal case is typically used for role names (for example, BillingAdministrator
), but the use of Pascal case isn't a strict requirement. Different casing schemes, such as camel case, kebab case, and snake case, are permitted. Using spaces in role names is also unusual but permitted. For example, billing administrator
is an unusual role name format in .NET apps but valid.
Additional resources
- Role template IDs (Entra documentation)
groupMembershipClaims
attribute (Entra documentation)- Add app roles to your application and receive them in the token (Entra documentation)
- Application roles (Azure documentation)
- Claims-based authorization in ASP.NET Core
- Role-based authorization in ASP.NET Core
- ASP.NET Core Blazor authentication and authorization