Skip to content

Add guidance on V1 and V2 STS tokens#36979

Open
guardrex wants to merge 8 commits into
mainfrom
guardrex/blazor-entra-oidc-v2-sts-tokens
Open

Add guidance on V1 and V2 STS tokens#36979
guardrex wants to merge 8 commits into
mainfrom
guardrex/blazor-entra-oidc-v2-sts-tokens

Conversation

@guardrex
Copy link
Copy Markdown
Collaborator

@guardrex guardrex commented Apr 10, 2026

Fixes #36978
Fixes #37030
Fixes #37031

Stephen ...

  • The convo that led to this is at the Blazor samples repo: BlazorWebAppEntraBff endpoints might need updating blazor-samples#654 (comment)
  • TL;DR on that convo (I wrote a 📖🙈😆) ... We spoke years ago about this and decided to just go with V1 tokens. I'm seeing now if we can expand coverage to include guidance on V2 STS tokens.
  • IDK if the 🧀 moved (perhaps ME-ID is less flexible on it than AAD of yesteryear), but the ME-ID authority URL requires a trailing slash now. This PR adds it where we show the V1 (sts.windows.net) URLs.
  • Adding a section on how to get the token (and token details) logged at an endpoint during development. I do not plan to add the code to the samples, only show it in the article in the Troubleshoot section. Thanks, @GC-brian-taylor! 🚀
  • Open questions for the new V2 STS token guidance section ...
    1. I'm currently only showing explicit token issuer validation with TokenValidationParameters for the web API (MinimalApiJwt). Should I also be doing that in the Blazor app's Program file?
    2. In the web API config for TokenValidationParameters, why is the ValidAudience just the client id and not the full audience passed to jwtOptions.Audience? If I try to use the full audience value there, it 💥 with a mismatch error with Azure and explicitly tells me that its just looking for the client id.

Internal previews

📄 File 🔗 Preview link
aspnetcore/blazor/security/blazor-web-app-with-entra.md aspnetcore/blazor/security/blazor-web-app-with-entra
aspnetcore/blazor/security/blazor-web-app-with-oidc.md aspnetcore/blazor/security/blazor-web-app-with-oidc

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds documentation to clarify V1 vs V2 Microsoft Entra STS token issuer formats and links OIDC guidance to the new Entra-specific section so readers can choose the correct authority/issuer settings.

Changes:

  • Adds a new STS token version section to the Entra Blazor Web App security article with V1/V2 authority examples and V2 migration notes.
  • Adds cross-references from the OIDC Blazor Web App security article to the Entra article’s STS token version guidance.
  • Expands authority examples in the Entra article to explicitly show both V1 and V2 issuer URL formats for ME-ID tenants.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
aspnetcore/blazor/security/blazor-web-app-with-oidc.md Adds repeated notes/cross-links pointing readers to Entra STS token version guidance.
aspnetcore/blazor/security/blazor-web-app-with-entra.md Adds V1/V2 authority examples and a new STS token version section with V2 migration guidance.

Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md Outdated
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md Outdated
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md
Comment thread aspnetcore/blazor/security/blazor-web-app-with-oidc.md
Comment thread aspnetcore/blazor/security/blazor-web-app-with-oidc.md
guardrex and others added 2 commits April 10, 2026 09:16
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@guardrex guardrex requested a review from halter73 April 10, 2026 13:19
@tdykstra
Copy link
Copy Markdown
Contributor

tdykstra commented Apr 15, 2026

I'll wait to see @halter73's review before adding mine.

@guardrex
Copy link
Copy Markdown
Collaborator Author

guardrex commented Apr 20, 2026

Thanks again, @GC-brian-taylor! If you look at the last commit, I'm going to see if we can add that troubleshooting guidance here. Makes sense, given that @halter73 has to review this for the other items anyway ... a time saver for him.

I changed it up a bit from what you did ...

  • Slightly different approach for the code that gets the header and token.
  • Used structured logging calls.
  • Logs the full token, so the dev can take it to an online decoder.
  • DEBUG config only, and I have a red warning (caution) about not logging tokens in production.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comment thread aspnetcore/blazor/security/includes/troubleshoot-server.md Outdated
Comment thread aspnetcore/blazor/security/includes/troubleshoot-server.md Outdated
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md Outdated
Comment thread aspnetcore/blazor/security/blazor-web-app-with-entra.md Outdated
Comment thread aspnetcore/blazor/security/blazor-web-app-with-oidc.md

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

requestedAccessTokenVersion in the app manifest controls the version of access tokens issued for that app as a resource (i.e., when it's the audience). For a Blazor Web App + MinimalApiJwt setup, the access token the BFF sends to the web API is issued for the web API's audience, so only the web API's app registration needs requestedAccessTokenVersion: 2. Setting it on the client app registration has no effect on the tokens consumed by MinimalApiJwt. Suggest narrowing this to just the web API registration as follows:

> * The STS version must be changed in the web API's (`MinimalApiJwt`) app registration in the Azure portal. Set the value of `requestedAccessTokenVersion` to `2` in the web API app registration's manifest. Entra issues access tokens in the version requested by the resource (audience) app registration, so this setting on the Blazor Web App's client registration has no effect on the tokens that `MinimalApiJwt` receives and validates.

try
{
var handler =
new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler instead of JwtSecurityTokenHandler. It's the newer, recommended handler. ASP.NET Core's JWT bearer middleware uses it by default in recent versions, and JwtSecurityTokenHandler is in maintenance mode.

var handler = 
    new Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler();
var jwtToken = handler.ReadJsonWebToken(token);
logger.LogDebug("Audience: {Audience}", 
    string.Join(", ", jwtToken.Audiences));
logger.LogDebug("Issuer: {Issuer}", jwtToken.Issuer);

jwtOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
// Ensure the issuer ends with /v2.0 if using the V2 endpoint
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting {TENANT ID} here must be the tenant GUID (matching the tid claim), not a domain like contoso.onmicrosoft.com — the iss claim for V2 work/school tokens is always the GUID form, so a domain-form ValidIssuer won't match. Suggest folding that into the existing comment:

Suggested change
// Ensure the issuer ends with /v2.0 if using the V2 endpoint
// Ensure the issuer ends with /v2.0 if using the V2 endpoint and that
// {TENANT ID} is the tenant GUID (matching the token's tid claim), not a domain

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants