ASP.NET Core 3.1中AddOpenIdConnect与AddJwtBearer中间件疑问
Hey there! Let's break down your questions step by step—since you're new to this deeper ASP.NET Core auth stuff, it's totally normal to hit these confusion points. First, let's clarify what each middleware does, then tackle your specific questions and the odd behaviors you're seeing.
First: Core Roles of the Two Middleware
AddOpenIdConnect(): Handles the full OpenID Connect authentication flow (like the authorization code flow you're using withResponseType = Code). It manages redirecting users to your OIDC authority, exchanging the authorization code for tokens (ID Token, Access Token, Refresh Token), validating the ID Token, and storing user claims + tokens in an authentication cookie (whenSaveTokens = true).AddJwtBearer(): Designed for validating Access Tokens sent in theAuthorization: Bearerheader (typically used for API endpoints). It doesn't handle user login/redirects—it just checks that incoming JWTs are valid, signed by your authority, and match the expected audience/issuer.
Quick Side Note: Why Are You Seeing Requests to /.well-known/oidc-configuration and /.well-known/keys?
Both middleware automatically fetch this metadata on startup (or first request) to:
- Get OIDC authority details (token endpoints, supported scopes, etc.) from
/.well-known/oidc-configuration - Retrieve public signing keys from
/.well-known/keysto verify the signature of JWTs (ID Tokens for OpenIdConnect, Access Tokens for JwtBearer)
This is all handled internally by the middleware—you don't need to write code for these requests.
Your Specific Questions Answered
1. Will AddJwtBearer() automatically validate ID Tokens after proper configuration?
Short answer: No—AddJwtBearer() is built to validate Access Tokens, not ID Tokens. The ID Token validation is handled entirely by AddOpenIdConnect() as part of the OIDC flow.
For AddJwtBearer(), if you set a valid Authority and Audience, it will automatically:
- Fetch the public keys from the authority's JWKS endpoint
- Validate the Access Token's signature, issuer, audience, lifetime, and other parameters you set in
TokenValidationParameters
The reason your ValidAudience change didn't break authentication is likely because your app is using the cookie authentication scheme (from AddOpenIdConnect()) by default, not the JwtBearer scheme. To trigger JwtBearer validation, you need to either:
- Set it as the default authentication scheme (e.g.,
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)) - Decorate your API controllers/actions with
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
2. If manual validation is needed, how to store JWKs fetched from /.well-known/keys?
You almost never need to manually store these—both middleware automatically cache the JWKs internally. If you do need access to them for custom logic, you can inject the IConfigurationManager<OpenIdConnectConfiguration> service into your code. For example:
private readonly IConfigurationManager<OpenIdConnectConfiguration> _configManager; public YourService(IConfigurationManager<OpenIdConnectConfiguration> configManager) { _configManager = configManager; } public async Task<IEnumerable<SecurityKey>> GetSigningKeysAsync() { var config = await _configManager.GetConfigurationAsync(CancellationToken.None); return config.SigningKeys; }
This gives you access to the same keys the middleware uses for validation.
3. How to get the Access/Refresh Token cookies and send the Refresh Token to the authority?
First, when you set SaveTokens = true in AddOpenIdConnect(), the tokens are stored encrypted in the authentication cookie (.AspNetCore.Cookies), which is why you don't see plaintext ey... JWTs in the cookie content. To retrieve them, use HttpContext.GetTokenAsync():
// Get Access Token var accessToken = await HttpContext.GetTokenAsync("access_token"); // Get Refresh Token var refreshToken = await HttpContext.GetTokenAsync("refresh_token");
To refresh your tokens, send a POST request to your authority's token endpoint (you can get this from the OIDC metadata) with these parameters:
grant_type: refresh_token refresh_token: [your_refresh_token] client_id: [your_client_id] client_secret: [your_client_secret] scope: [your_scopes (optional, if you want the same scopes)]
You can use HttpClient to send this request, then update the stored tokens using HttpContext.SignInAsync() with the new tokens in AuthenticationProperties.
4. Can the middleware's options.Events solve these issues?
Absolutely—events let you hook into key parts of the auth flow to customize behavior:
- For
AddOpenIdConnect():OnTokenReceived: Capture tokens right after they're retrieved from the authorityOnAuthenticationFailed: Debug why ID Token validation failedOnAuthorizationCodeReceived: Customize the code exchange process
- For
AddJwtBearer():OnTokenValidated: Add custom validation logic (e.g., check additional claims)OnAuthenticationFailed: See why JWT validation failed (this would have told you why changingValidAudiencedidn't trigger an error—if the scheme wasn't being used)OnMessageReceived: Customize how the Access Token is retrieved from the request
For example, if you want to log JWT validation failures, you could add this to AddJwtBearer():
options.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { // Log the error details Console.WriteLine($"JWT Validation Failed: {context.Exception.Message}"); return Task.CompletedTask; } };
5. What operations do these middleware handle automatically?
AddOpenIdConnect():
- Redirects users to the OIDC authority's login page when an unauthenticated user accesses a protected resource
- Handles the authorization code exchange to get ID Token, Access Token, and Refresh Token
- Validates the ID Token's signature, issuer, audience, and lifetime automatically
- Stores user claims in the authentication cookie
- Saves tokens (when
SaveTokens = true) in encrypted form in the cookie - Note: It does not automatically refresh tokens in the background—you need to handle this manually (using the Refresh Token and
HttpContext.SignInAsync()) or use limited built-in refresh logic (triggered whenRefreshOnIssuerKeyNotFound = true).
AddJwtBearer():
- Automatically extracts the Access Token from the
Authorization: Bearerheader - Fetches and caches public signing keys from the OIDC authority's JWKS endpoint
- Validates the Access Token's signature, issuer, audience, lifetime, and other parameters in
TokenValidationParameters - Handles clock skew (via
ClockSkewsetting) to account for minor time differences between servers - Note: It doesn't handle token refresh or user login—its sole job is validating incoming Access Tokens.
内容的提问来源于stack exchange,提问作者deathcat05

