From 9bde900abfef549080dd78ca92d3eef44254ceb0 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:03:36 -0400 Subject: [PATCH 1/8] Add guidance on V1 and V2 STS tokens --- .../security/blazor-web-app-with-entra.md | 54 ++++++++++++++++++- .../security/blazor-web-app-with-oidc.md | 10 ++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 767dfcf9c61f..b9b615f11da0 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -138,12 +138,22 @@ jwtOptions.Authority = "{AUTHORITY}"; The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. -If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider: +If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider. + +V1 STS token format: ```csharp jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` +V2 STS token format: + +```csharp +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; +``` + +For more information on V2 STS tokens, see the [STS token version](#sts-token-version) section. + If the app is registered in a Microsoft Entra External ID tenant: ```csharp @@ -434,12 +444,22 @@ jwtOptions.Authority = "{AUTHORITY}"; The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. -If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider: +If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider. + +V1 STS token format: ```csharp jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` +V2 STS token format: + +```csharp +jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; +``` + +For more information on V2 STS tokens, see the [STS token version](#sts-token-version) section. + If the app is registered in a Microsoft Entra External ID tenant: ```csharp @@ -849,6 +869,8 @@ In the `MinimalApiJwt` project, add the following app settings configuration to }, ``` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see the [STS token version](#sts-token-version) section. + Update the placeholders in the preceding configuration to match the values that the app uses in the `Program` file: * `{TENANT ID (WEB API)}`: The Tenant Id of the web API. @@ -860,6 +882,8 @@ Authority formats adopt the following patterns: * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see the [STS token version](#sts-token-version) section. + Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): * ME-ID tenant type: `api://{CLIENT ID}` @@ -1157,6 +1181,32 @@ Server-side Blazor Web Apps hosted in a web farm or cluster of machines must ado We also recommend using a shared [Data Protection](xref:security/data-protection/introduction) key ring in production, even when the app uses the Interactive WebAssembly render mode exclusively for client-side rendering (no Blazor circuits). +## STS token version + +There are two types of token formats, named Version 1 (V1) and Version 2 (V2). In Azure's security token services (STS), the V1 format uses the `sts.windows.net` domain as the issuer, while the V2 format uses the `login.microsoftonline.com` domain as issuer. V2 supports additional features, such as authenticating personal accounts and OpenID protocols. + +This article and its accompanying sample apps adopt V1 STS tokens. To adopt V2 tokens, make the following changes: + +* The STS version must be changed in the apps' registrations in the Azure portal. Set the value of `requestedAccessTokenVersion` to `2` in the apps' manifests, both in the app's registration and the web API's (`MinimalApiJwt`) registration. +* Use the V2 authority URL format (example: `https://login.microsoftonline.com/{TENANT ID}/v2.0`, where the `{TENANT ID}` placeholder is the tenant ID). +* In the web API (`MinimalApiJwt`), explicitly validate the issuer: + + ```csharp + jwtOptions.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + // Ensure the issuer ends with /v2.0 if using the V2 endpoint + ValidIssuer = "https://login.microsoftonline.com/{TENANT ID}/v2.0", + ValidateAudience = true, + ValidAudience = "{WEB API CLIENT ID}", + ValidateLifetime = true + }; + ``` + + The `{WEB API CLIENT ID}` placeholder in the preceding example is only the client ID, not the full value passed to the `Audience` property. + +For more information, see [Access tokens in the Microsoft identity platform: Token formats](/entra/identity-platform/access-tokens#token-formats). + ## Troubleshoot [!INCLUDE[](~/blazor/security/includes/troubleshoot-server.md)] diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index 81e79bf26364..88b6b59e0425 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -181,6 +181,8 @@ ME-ID tenant Authority example: jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . + AAD B2C tenant Authority example: ```csharp @@ -529,6 +531,8 @@ ME-ID tenant Authority example: jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . + AAD B2C tenant Authority example: ```csharp @@ -876,6 +880,8 @@ ME-ID tenant Authority example: jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; ``` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . + AAD B2C tenant Authority example: ```csharp @@ -1200,6 +1206,8 @@ In the `MinimalApiJwt` project, add the following app settings configuration to }, ``` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . + Update the placeholders in the preceding configuration to match the values that the app uses in the `Program` file: * `{TENANT ID (WEB API)}`: The Tenant Id of the web API. @@ -1211,6 +1219,8 @@ Authority formats adopt the following patterns: * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` +The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . + Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): * ME-ID tenant type: `api://{CLIENT ID}` From c57d86e9b20ec48d7cdc14fcf4a43bab4e50370d Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:16:40 -0400 Subject: [PATCH 2/8] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- aspnetcore/blazor/security/blazor-web-app-with-entra.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index b9b615f11da0..80cedca838a4 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -138,7 +138,7 @@ jwtOptions.Authority = "{AUTHORITY}"; The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. -If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider. +If the app is registered in an ME-ID tenant, the authority should match the issuer (`iss`) of the JWT returned by the identity provider. V1 STS token format: @@ -444,7 +444,7 @@ jwtOptions.Authority = "{AUTHORITY}"; The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` and a directory name of `contoso`. -If the app is registered in an ME-ID tenant, the authority should match the issurer (`iss`) of the JWT returned by the identity provider. +If the app is registered in an ME-ID tenant, the authority should match the issuer (`iss`) of the JWT returned by the identity provider. V1 STS token format: From ea681a1b0961bfced9d1dcf8f7946de9741c46b9 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:18:26 -0400 Subject: [PATCH 3/8] Updates --- aspnetcore/blazor/security/blazor-web-app-with-entra.md | 2 +- aspnetcore/blazor/security/blazor-web-app-with-oidc.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 80cedca838a4..c32151f21ed5 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -882,7 +882,7 @@ Authority formats adopt the following patterns: * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` -The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see the [STS token version](#sts-token-version) section. +The preceding example for the ME-ID tenant type uses the V1 STS token URL format. For guidance on V2 STS tokens, see the [STS token version](#sts-token-version) section. Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index 88b6b59e0425..2a08e3b4969c 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -1219,7 +1219,7 @@ Authority formats adopt the following patterns: * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` -The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . +The preceding example for the ME-ID tenant type uses the V1 STS token URL format. For guidance on V2 STS tokens, see . Audience formats adopt the following patterns (`{CLIENT ID}` is the Client Id of the web API; `{DIRECTORY NAME}` is the directory name, for example, `contoso`): From e39628a6943fbed5c7425a201134bd0849844232 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 20 Apr 2026 08:48:28 -0400 Subject: [PATCH 4/8] Update V1 URLs --- .../blazor/security/blazor-web-app-with-entra.md | 8 ++++---- aspnetcore/blazor/security/blazor-web-app-with-oidc.md | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index c32151f21ed5..41f5d3b2688f 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -143,7 +143,7 @@ If the app is registered in an ME-ID tenant, the authority should match the issu V1 STS token format: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` V2 STS token format: @@ -449,7 +449,7 @@ If the app is registered in an ME-ID tenant, the authority should match the issu V1 STS token format: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` V2 STS token format: @@ -862,7 +862,7 @@ In the `MinimalApiJwt` project, add the following app settings configuration to "Authentication": { "Schemes": { "Bearer": { - "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}", + "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/", "ValidAudiences": ["{APP ID URI (WEB API)}"] } } @@ -878,7 +878,7 @@ Update the placeholders in the preceding configuration to match the values that Authority formats adopt the following patterns: -* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}` +* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/` * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index 2a08e3b4969c..94b57fe3b2bf 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -178,7 +178,7 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . @@ -528,7 +528,7 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . @@ -877,7 +877,7 @@ The format of the Authority depends on the type of tenant in use. The following ME-ID tenant Authority example: ```csharp -jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee"; +jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` The preceding example uses the V1 STS token URL format. For guidance on V2 STS tokens, see . @@ -1199,7 +1199,7 @@ In the `MinimalApiJwt` project, add the following app settings configuration to "Authentication": { "Schemes": { "Bearer": { - "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}", + "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}/", "ValidAudiences": [ "{APP ID URI (WEB API)}" ] } } @@ -1215,7 +1215,7 @@ Update the placeholders in the preceding configuration to match the values that Authority formats adopt the following patterns: -* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}` +* ME-ID tenant type: `https://sts.windows.net/{TENANT ID}/` * Microsoft Entra External ID: `https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0` * B2C tenant type: `https://login.microsoftonline.com/{TENANT ID}/v2.0` From 1bdf37f9bacc24faeb2d8fdf3ad8e52573427d79 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 20 Apr 2026 10:42:48 -0400 Subject: [PATCH 5/8] Add a troubleshoot section on token details --- .../security/includes/troubleshoot-server.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/aspnetcore/blazor/security/includes/troubleshoot-server.md b/aspnetcore/blazor/security/includes/troubleshoot-server.md index 6c22bdd334fc..073744ae7b1f 100644 --- a/aspnetcore/blazor/security/includes/troubleshoot-server.md +++ b/aspnetcore/blazor/security/includes/troubleshoot-server.md @@ -158,3 +158,51 @@ The following `UserClaims` component can be used directly in apps or serve as th } } ``` + +### Inspect the access token + +Obtaining the access token during development is often helpful when troubleshooting app and Azure configuration problems. In the following example for a weather forecast endpoint, the bearer token and token details are logged when in the DEBUG configuration. You can decode the token using an online JWT token decoder, such as the [Microsoft JWT token decoder](https://jwt.ms/), or log details from the token in C#, as the following example demonstrates. + +> [!CAUTION] +> In production, avoid logging the token or its contents. + +```csharp +app.MapGet("/weather-forecast", (HttpContext context, ILogger logger) => +{ +#if DEBUG + var authHeader = context.Request.Headers.Authorization.FirstOrDefault(v => + v != null && + v.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)); + + if (authHeader is not null) + { + var token = authHeader["Bearer ".Length..].Trim(); + logger.LogDebug("Token: {Token}", token); + + try + { + var handler = + new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler(); + var jwtToken = handler.ReadJwtToken(token); + logger.LogDebug("Audience: {Audience}", + string.Join(", ", jwtToken.Audiences)); + logger.LogDebug("Issuer: {Issuer}", jwtToken.Issuer); + } + catch (Exception ex) + { + logger.LogError("Failed to decode token: {Message}", ex.Message); + } + } +#endif + + var forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}).RequireAuthorization(); +``` From 45830a117f17cc197269a469fea80091a01f8a1e Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Mon, 20 Apr 2026 10:55:15 -0400 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- aspnetcore/blazor/security/includes/troubleshoot-server.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/security/includes/troubleshoot-server.md b/aspnetcore/blazor/security/includes/troubleshoot-server.md index 073744ae7b1f..ec18ab45b4f0 100644 --- a/aspnetcore/blazor/security/includes/troubleshoot-server.md +++ b/aspnetcore/blazor/security/includes/troubleshoot-server.md @@ -161,7 +161,7 @@ The following `UserClaims` component can be used directly in apps or serve as th ### Inspect the access token -Obtaining the access token during development is often helpful when troubleshooting app and Azure configuration problems. In the following example for a weather forecast endpoint, the bearer token and token details are logged when in the DEBUG configuration. You can decode the token using an online JWT token decoder, such as the [Microsoft JWT token decoder](https://jwt.ms/), or log details from the token in C#, as the following example demonstrates. +Obtaining the access token during development is often helpful when troubleshooting app and Azure configuration problems. In the following example for a weather forecast endpoint, the bearer token and token details are logged only when the app is compiled with the `DEBUG` symbol, which is typically a Debug build. You can decode the token using an online JWT token decoder, such as the [Microsoft JWT token decoder](https://jwt.ms/), or log details from the token in C#, as the following example demonstrates. > [!CAUTION] > In production, avoid logging the token or its contents. @@ -190,7 +190,7 @@ app.MapGet("/weather-forecast", (HttpContext context, ILogger logger) = } catch (Exception ex) { - logger.LogError("Failed to decode token: {Message}", ex.Message); + logger.LogError(ex, "Failed to decode token."); } } #endif From a4cf7c809faa5342c8712a5a4566f575114bb1dd Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 20 Apr 2026 11:01:15 -0400 Subject: [PATCH 7/8] React to Copilot suggestions for V1/V2 URIs --- .../blazor/security/blazor-web-app-with-entra.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 41f5d3b2688f..779181f2eb5d 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -140,13 +140,13 @@ The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` If the app is registered in an ME-ID tenant, the authority should match the issuer (`iss`) of the JWT returned by the identity provider. -V1 STS token format: +V1 STS token endpoint: ```csharp jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` -V2 STS token format: +V2 STS token endpoint: ```csharp jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; @@ -446,13 +446,13 @@ The following examples use a Tenant ID of `aaaabbbb-0000-cccc-1111-dddd2222eeee` If the app is registered in an ME-ID tenant, the authority should match the issuer (`iss`) of the JWT returned by the identity provider. -V1 STS token format: +V1 STS token endpoint: ```csharp jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee/"; ``` -V2 STS token format: +V2 STS token endpoint: ```csharp jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0"; @@ -1183,12 +1183,12 @@ We also recommend using a shared [Data Protection](xref:security/data-protection ## STS token version -There are two types of token formats, named Version 1 (V1) and Version 2 (V2). In Azure's security token services (STS), the V1 format uses the `sts.windows.net` domain as the issuer, while the V2 format uses the `login.microsoftonline.com` domain as issuer. V2 supports additional features, such as authenticating personal accounts and OpenID protocols. +There are two types of token URIs, named Version 1 (V1) and Version 2 (V2). In Azure's security token services (STS), the V1 endpoint uses the `sts.windows.net` domain as the issuer, while the V2 endpoint uses the `login.microsoftonline.com` domain as the issuer. V2 supports additional features, such as authenticating personal accounts and OpenID Connect (OIDC) protocols. This article and its accompanying sample apps adopt V1 STS tokens. To adopt V2 tokens, make the following changes: * The STS version must be changed in the apps' registrations in the Azure portal. Set the value of `requestedAccessTokenVersion` to `2` in the apps' manifests, both in the app's registration and the web API's (`MinimalApiJwt`) registration. -* Use the V2 authority URL format (example: `https://login.microsoftonline.com/{TENANT ID}/v2.0`, where the `{TENANT ID}` placeholder is the tenant ID). +* Use the V2 authority URL endpoint (example: `https://login.microsoftonline.com/{TENANT ID}/v2.0`, where the `{TENANT ID}` placeholder is the tenant ID). * In the web API (`MinimalApiJwt`), explicitly validate the issuer: ```csharp From a74884e22422c44dd6b090e6345854aa33b1a603 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:28:27 -0400 Subject: [PATCH 8/8] Cover ValidAudiences and ValidAudience --- .../security/blazor-web-app-with-entra.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/security/blazor-web-app-with-entra.md b/aspnetcore/blazor/security/blazor-web-app-with-entra.md index 779181f2eb5d..bed1138e4093 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-entra.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-entra.md @@ -1198,12 +1198,25 @@ This article and its accompanying sample apps adopt V1 STS tokens. To adopt V2 t // Ensure the issuer ends with /v2.0 if using the V2 endpoint ValidIssuer = "https://login.microsoftonline.com/{TENANT ID}/v2.0", ValidateAudience = true, - ValidAudience = "{WEB API CLIENT ID}", + ValidAudiences = new[] { "{WEB API CLIENT ID 1}", "{WEB API CLIENT ID 2}", ... }, ValidateLifetime = true }; ``` - The `{WEB API CLIENT ID}` placeholder in the preceding example is only the client ID, not the full value passed to the `Audience` property. + Instead of setting the property, you can specify a single valid audience with : + + ```csharp + ValidAudience = "{WEB API CLIENT ID}", + ``` + + The `{WEB API CLIENT ID}` placeholders in the preceding examples are ***only the client IDs***, not the full values passed to the `Audience` property. + + To supply a collection of valid audiences in an app that [configures Identity from app settings](#supply-configuration-with-the-json-configuration-provider-app-settings), you can use the following code to obtain the valid audiences configuration: + + ```csharp + ValidAudiences = builder.Configuration.GetSection( + "Authentication:Schemes:Bearer:ValidAudiences").Get(), + ``` For more information, see [Access tokens in the Microsoft identity platform: Token formats](/entra/identity-platform/access-tokens#token-formats).