Scopes, Claims, and Token Behavior in Blazor Server with Entra ID and Microsoft Graph¶
This document provides a detailed explanation of scopes, claims, and tokens in a Blazor Server application integrated with Microsoft Entra ID (Azure AD) and Microsoft Graph. It also covers their behavioral effects when APIs are accessed via a gateway, and explains the role of the issuer and authority. This guidance is intended for technical IT staff including project managers, architects, security teams, and lead developers.
Scopes vs Claims¶
Scopes (Permissions)¶
- Definition: Scopes represent what an application is allowed to do.
- Where used: Requested during token acquisition and validated by the API or gateway.
- Behavioral effect:
- They appear in the access token as the
scp
claim. - APIs enforce scopes to decide if a request is authorized.
- Example: This means the token holder can read profile info and email.
Claims (Identity Attributes)¶
- Definition: Claims describe who the user is and additional attributes.
- Where used: Issued in ID tokens and access tokens.
- Behavioral effect:
- Claims affect application logic (e.g., roles, display name, tenant ID).
- They do not change what APIs you can call (that is scope-driven).
Example claims in an ID token:
{
"name": "Alice Example",
"preferred_username": "alice@contoso.com",
"roles": ["Admin", "User"],
"iss": "https://login.microsoftonline.com/{tenantId}/v2.0"
}
Token Types and Their Purpose¶
ID Token¶
- Confirms who the user is.
- Contains claims used for personalization and authorization inside Blazor.
- Not used when calling APIs.
Access Token¶
- Confirms what the client app is allowed to do.
- Contains
scp
claim (scopes) and some identity claims. - Sent in the
Authorization: Bearer <token>
header when calling Microsoft Graph or your APIs.
Refresh Token¶
- Used to silently request new access tokens when old ones expire.
- Managed automatically by MSAL in Blazor with
.AddInMemoryTokenCaches()
. - Not sent to your APIs.
How IClaimsTransformation
Fits In¶
- Runs after authentication to transform the in-app
ClaimsPrincipal
. - Does not modify the actual ID token or access token issued by Entra.
- Useful for mapping Entra claims (e.g.,
groups
) into app-specific roles.
Example:
public class CustomClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var identity = (ClaimsIdentity)principal.Identity!;
if (identity.HasClaim(c => c.Type == "groups" && c.Value == "group-id-here"))
{
identity.AddClaim(new Claim(ClaimTypes.Role, "FinanceAdmin"));
}
return Task.FromResult(principal);
}
}
π This affects only Blazorβs local authorization checks, not downstream API calls.
Authority and Issuer¶
- Authority: URL MSAL uses to authenticate and request tokens.
- Provides metadata endpoints (keys, discovery, etc.).
-
Defines the tenant/policy for authentication.
-
Issuer (
iss
) claim: Inside tokens, confirms who issued the token. - APIs and gateways validate that the
iss
matches the configured authority. - Prevents tokens from other tenants/issuers being accepted.
Example Configuration and Flow in Blazor¶
Startup configuration:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read", "Mail.Read" })
.AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
.AddInMemoryTokenCaches();
Component requiring Graph permissions:
[AuthorizeForScopes(Scopes = new[] { "User.Read" })]
public class GraphComponent : ComponentBase
{
[Inject]
GraphServiceClient GraphClient { get; set; } = default!;
private string? displayName;
protected override async Task OnInitializedAsync()
{
var me = await GraphClient.Me.Request().GetAsync();
displayName = me.DisplayName;
}
}
Behavior:
- [AuthorizeForScopes]
ensures the access token in cache has User.Read
.
- If not, MSAL requests a new access token with the required scope.
- Access token is not altered by claim transformations.
Sequence Diagram: Authentication and API Call Flow¶
sequenceDiagram
participant UI as Blazor UI
participant Blazor as Blazor Server
participant Entra as Entra ID (Azure AD)
participant Gateway as WSO2 API Manager
participant API as Downstream API / Graph
UI ->> Blazor: User signs in
Blazor ->> Entra: Auth request with scopes (User.Read, Mail.Read)
Entra -->> Blazor: ID Token + Access Token
Blazor ->> Blazor: Build ClaimsPrincipal (apply IClaimsTransformation)
UI ->> Blazor: Request data via GraphComponent
Blazor ->> Entra: Acquire Access Token for Graph (User.Read)
Entra -->> Blazor: Access Token with scp=User.Read
Blazor ->> Gateway: Call API with Bearer token
Gateway ->> Entra: Validate token (signature, issuer, scopes)
Gateway ->> API: Forward request if valid
API -->> Gateway: Response
Gateway -->> Blazor: Response
Blazor -->> UI: Render data (e.g., displayName)
Additional Considerations with WSO2 API Manager¶
When using WSO2 API Manager (APIM) as the gateway:
Token Validation in WSO2¶
- WSO2 expects self-contained JWT access tokens.
- Validates:
- Signature against trusted public keys.
- Standard claims (
iss
,sub
,exp
,iat
). - Scopes (
scp
orscope
) for API access.
Claim Mapping and Scope Translation¶
- Entra tokens use
scp
for scopes; WSO2 may expectscope
. - Use claim mapping in WSO2 to align claims.
- Scope enforcement is configurable per API definition.
Azure AD Integration¶
- Azure AD is not natively supported as a WSO2 Key Manager.
- Options:
- Implement a custom key manager in WSO2 to validate Entra tokens directly.
- Or use a token exchange flow (exchange Entra-issued token for a WSO2-recognized token).
Claim-Based Access Policies¶
- WSO2 supports JWT claim-based access validators.
- You can enforce policies like:
- Restrict access to users from specific tenant IDs.
- Require a role claim (e.g.,
roles: Admin
).
Backend Authentication¶
- WSO2 can manage its own OAuth2 credentials when authenticating to backends.
- Use OAuth2 endpoint security with grant types such as client credentials.
- Supports Redis caching for OAuth state across distributed gateways.
Scope Allowlisting¶
- Certain scopes can be allowlisted to bypass role checks.
- Configure allowlisting in
deployment.toml
if some scopes should always pass validation.
Security Best Practices¶
- Request least-privilege scopes β never ask for more than you need.
- Enforce scope checks at WSO2 gateway/API using the
scp
orscope
claim. - Use claims transformations only locally β do not rely on them for API security.
- Validate issuer and audience in every API/gateway.
- Rely on MSAL for token refresh and caching β do not store tokens manually.
- Use
[AuthorizeForScopes]
to ensure tokens have necessary permissions before API calls. - Configure WSO2 to:
- Trust Entra public signing keys.
- Map claims as needed (e.g.,
scp
βscope
). - Enforce claim-based access control for sensitive APIs.
Key Takeaways¶
- Scopes = Permissions (what you can do, validated by APIs/gateway).
- Claims = Identity attributes (who you are, used by apps for authorization/UI).
- ID Token = Establishes user identity.
- Access Token = Grants permissions to call APIs.
- Refresh Token = Silently gets new access tokens.
- Claims transformations only affect local app logic, not tokens sent downstream.
- Authority/Issuer ensure tokens are trusted and from the correct tenant.
- WSO2 APIM must be configured to:
- Accept and validate Entra-issued JWTs.
- Enforce scopes and claims consistently.
- Optionally use token exchange or custom key manager if Entra tokens are not directly consumable.
π By clearly separating scope enforcement (at WSO2 gateway/API) from claims usage (inside Blazor) and understanding token lifecycles, you can build secure Blazor Server applications aligned with enterprise security policies.