public class AuthCodeJwtBearerOptions : IConfigureNamedOptions<JwtBearerOptions>{private readonly IClaimsTransformation _claimsTransformation;private readonly ConfigurationManager<OpenIdConnectConfiguration> _configurationManager;private readonly string _name;public AuthCodeJwtBearerOptions(IOptions<TidV4OAuthSettings> tidV4OAuthOptions,IClaimsTransformation claimsTransformation){_name = "AuthCode";_claimsTransformation = claimsTransformation;_configurationManager =new ConfigurationManager<OpenIdConnectConfiguration>(tidV4OAuthOptions.Value.WellknownUrl,new OpenIdConnectConfigurationRetriever());}public void Configure(JwtBearerOptions options){var task = Task.Run(async () => await GetTokenValidationParametersAsync());options.TokenValidationParameters = task.Result;options.Events = new JwtBearerEvents { OnTokenValidated = OnTokenValidated };}public void Configure(string name, JwtBearerOptions options){if(!name.Equals(_name)){return;} Configure(options);}private async Task<TokenValidationParameters> GetTokenValidationParametersAsync(){var cancellationToken = new CancellationToken();var openIdConnectConfiguration = await _configurationManager.GetConfigurationAsync(cancellationToken);return new TokenValidationParameters{ValidateIssuerSigningKey = true,IssuerSigningKeys = openIdConnectConfiguration?.SigningKeys,ValidateAudience = false,ValidateIssuer = true,ValidIssuer = openIdConnectConfiguration?.Issuer,ValidateLifetime = true};}private async Task OnTokenValidated(TokenValidatedContext context){if (context.Principal == null){return;}//whatever you need to do once validated including claims transformationcontext.Principal = await _claimsTransformation.TransformAsync(context.Principal);}}
Repeat the above for other schemes that you want to support, switching the _name
, token validation parameters, and event logic as needed. I did this for "ClientCredentials" for now.
Now wire it up in your pipeline
serviceCollection.AddAuthentication().AddJwtBearer("AuthCode", _ => { }).AddJwtBearer("ClientCredentials", _ => { });serviceCollection.ConfigureOptions<ClientCredentialsJwtBearerOptions>();serviceCollection.ConfigureOptions<AuthCodeJwtBearerOptions>();serviceCollection.AddAuthorization(options =>{var authCodePolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().AddAuthenticationSchemes("AuthCode").Build();var clientCredentialsPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().AddAuthenticationSchemes("ClientCredentials").Build();var allPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().AddAuthenticationSchemes("AuthCode", "ClientCredentials").Build();options.AddPolicy("AuthCodeOnly", authCodePolicy);options.AddPolicy("ClientCredentialsOnly", clientCredentialsPolicy);options.AddPolicy( "AllPolicies", allPolicy);options.DefaultPolicy = options.GetPolicy("AuthCodeOnly")!;});
Again, huge thanks to Jeremy for the guidance on the options. And also to Marc for correcting the botch job formatting for my first Stack Overflow post.