private static void AddMicrosoftIdentityWebApiImplementation( AuthenticationBuilder builder, Action <JwtBearerOptions> configureJwtBearerOptions, Action <MicrosoftIdentityOptions> configureMicrosoftIdentityOptions, string jwtBearerScheme, bool subscribeToJwtBearerMiddlewareDiagnosticsEvents) { builder.AddJwtBearer(jwtBearerScheme, configureJwtBearerOptions); builder.Services.Configure(jwtBearerScheme, configureMicrosoftIdentityOptions); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton <IValidateOptions <MicrosoftIdentityOptions>, MicrosoftIdentityOptionsValidation>()); builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(); builder.Services.TryAddSingleton <MicrosoftIdentityIssuerValidatorFactory>(); builder.Services.AddOptions <AadIssuerValidatorOptions>(); if (subscribeToJwtBearerMiddlewareDiagnosticsEvents) { builder.Services.AddSingleton <IJwtBearerMiddlewareDiagnostics, JwtBearerMiddlewareDiagnostics>(); } // Change the authentication configuration to accommodate the Microsoft identity platform endpoint (v2.0). builder.Services.AddOptions <JwtBearerOptions>(jwtBearerScheme) .Configure <IServiceProvider, IOptionsMonitor <MicrosoftIdentityOptions> >((options, serviceProvider, microsoftIdentityOptionsMonitor) => { var microsoftIdentityOptions = microsoftIdentityOptionsMonitor.Get(jwtBearerScheme); if (string.IsNullOrWhiteSpace(options.Authority)) { options.Authority = AuthorityHelpers.BuildAuthority(microsoftIdentityOptions); } // This is a Microsoft identity platform web API options.Authority = AuthorityHelpers.EnsureAuthorityIsV2(options.Authority); if (options.TokenValidationParameters.AudienceValidator == null && options.TokenValidationParameters.ValidAudience == null && options.TokenValidationParameters.ValidAudiences == null) { RegisterValidAudience registerAudience = new RegisterValidAudience(); registerAudience.RegisterAudienceValidation( options.TokenValidationParameters, microsoftIdentityOptions); } // If the developer registered an IssuerValidator, do not overwrite it if (options.TokenValidationParameters.ValidateIssuer && options.TokenValidationParameters.IssuerValidator == null) { // Instead of using the default validation (validating against a single tenant, as we do in line of business apps), // we inject our own multi-tenant validation logic (which even accepts both v1.0 and v2.0 tokens) MicrosoftIdentityIssuerValidatorFactory microsoftIdentityIssuerValidatorFactory = serviceProvider.GetRequiredService <MicrosoftIdentityIssuerValidatorFactory>(); options.TokenValidationParameters.IssuerValidator = microsoftIdentityIssuerValidatorFactory.GetAadIssuerValidator(options.Authority).Validate; } // If you provide a token decryption certificate, it will be used to decrypt the token if (microsoftIdentityOptions.TokenDecryptionCertificates != null) { IEnumerable <X509Certificate2?> certificates = DefaultCertificateLoader.LoadAllCertificates(microsoftIdentityOptions.TokenDecryptionCertificates); IEnumerable <X509SecurityKey> keys = certificates.Select(c => new X509SecurityKey(c)); options.TokenValidationParameters.TokenDecryptionKeys = keys; } if (options.Events == null) { options.Events = new JwtBearerEvents(); } // When an access token for our own web API is validated, we add it to MSAL.NET's cache so that it can // be used from the controllers. var tokenValidatedHandler = options.Events.OnTokenValidated; options.Events.OnTokenValidated = async context => { if (!microsoftIdentityOptions.AllowWebApiToBeAuthorizedByACL && !context !.Principal !.Claims.Any(x => x.Type == ClaimConstants.Scope || x.Type == ClaimConstants.Scp || x.Type == ClaimConstants.Roles || x.Type == ClaimConstants.Role)) { throw new UnauthorizedAccessException(IDWebErrorMessage.NeitherScopeOrRolesClaimFoundInToken); } await tokenValidatedHandler(context).ConfigureAwait(false); }; if (subscribeToJwtBearerMiddlewareDiagnosticsEvents) { var diagnostics = serviceProvider.GetRequiredService <IJwtBearerMiddlewareDiagnostics>(); diagnostics.Subscribe(options.Events); } }); }
private static void AddMicrosoftIdentityWebApiImplementation( AuthenticationBuilder builder, Action <JwtBearerOptions> configureJwtBearerOptions, Action <MicrosoftIdentityOptions> configureMicrosoftIdentityOptions, string jwtBearerScheme, bool subscribeToJwtBearerMiddlewareDiagnosticsEvents) { builder.AddJwtBearer(jwtBearerScheme, configureJwtBearerOptions); builder.Services.Configure(jwtBearerScheme, configureMicrosoftIdentityOptions); builder.Services.AddHttpContextAccessor(); builder.Services.AddHttpClient(); builder.Services.TryAddSingleton <MicrosoftIdentityIssuerValidatorFactory>(); builder.Services.AddRequiredScopeAuthorization(); builder.Services.AddRequiredScopeOrAppPermissionAuthorization(); builder.Services.AddOptions <AadIssuerValidatorOptions>(); if (subscribeToJwtBearerMiddlewareDiagnosticsEvents) { builder.Services.AddTransient <IJwtBearerMiddlewareDiagnostics, JwtBearerMiddlewareDiagnostics>(); } // Change the authentication configuration to accommodate the Microsoft identity platform endpoint (v2.0). builder.Services.AddOptions <JwtBearerOptions>(jwtBearerScheme) .Configure <IServiceProvider, IOptionsMonitor <MergedOptions>, IOptionsMonitor <MicrosoftIdentityOptions>, IOptions <MicrosoftIdentityOptions> >(( options, serviceProvider, mergedOptionsMonitor, msIdOptionsMonitor, msIdOptions) => { MicrosoftIdentityBaseAuthenticationBuilder.SetIdentityModelLogger(serviceProvider); MergedOptions mergedOptions = mergedOptionsMonitor.Get(jwtBearerScheme); MergedOptions.UpdateMergedOptionsFromJwtBearerOptions(options, mergedOptions); MergedOptions.UpdateMergedOptionsFromMicrosoftIdentityOptions(msIdOptions.Value, mergedOptions); MergedOptions.UpdateMergedOptionsFromMicrosoftIdentityOptions(msIdOptionsMonitor.Get(jwtBearerScheme), mergedOptions); MergedOptionsValidation.Validate(mergedOptions); if (string.IsNullOrWhiteSpace(options.Authority)) { options.Authority = AuthorityHelpers.BuildAuthority(mergedOptions); } // This is a Microsoft identity platform web API options.Authority = AuthorityHelpers.EnsureAuthorityIsV2(options.Authority); if (options.TokenValidationParameters.AudienceValidator == null && options.TokenValidationParameters.ValidAudience == null && options.TokenValidationParameters.ValidAudiences == null) { RegisterValidAudience registerAudience = new RegisterValidAudience(); registerAudience.RegisterAudienceValidation( options.TokenValidationParameters, mergedOptions); } // If the developer registered an IssuerValidator, do not overwrite it if (options.TokenValidationParameters.ValidateIssuer && options.TokenValidationParameters.IssuerValidator == null) { // Instead of using the default validation (validating against a single tenant, as we do in line of business apps), // we inject our own multi-tenant validation logic (which even accepts both v1.0 and v2.0 tokens) MicrosoftIdentityIssuerValidatorFactory microsoftIdentityIssuerValidatorFactory = serviceProvider.GetRequiredService <MicrosoftIdentityIssuerValidatorFactory>(); options.TokenValidationParameters.IssuerValidator = microsoftIdentityIssuerValidatorFactory.GetAadIssuerValidator(options.Authority).Validate; } // If you provide a token decryption certificate, it will be used to decrypt the token if (mergedOptions.TokenDecryptionCertificates != null) { DefaultCertificateLoader.UserAssignedManagedIdentityClientId = mergedOptions.UserAssignedManagedIdentityClientId; IEnumerable <X509Certificate2?> certificates = DefaultCertificateLoader.LoadAllCertificates(mergedOptions.TokenDecryptionCertificates); IEnumerable <X509SecurityKey> keys = certificates.Select(c => new X509SecurityKey(c)); options.TokenValidationParameters.TokenDecryptionKeys = keys; } if (options.Events == null) { options.Events = new JwtBearerEvents(); } // When an access token for our own web API is validated, we add it to MSAL.NET's cache so that it can // be used from the controllers. if (!mergedOptions.AllowWebApiToBeAuthorizedByACL) { ChainOnTokenValidatedEventForClaimsValidation(options.Events, jwtBearerScheme); } if (subscribeToJwtBearerMiddlewareDiagnosticsEvents) { var diagnostics = serviceProvider.GetRequiredService <IJwtBearerMiddlewareDiagnostics>(); diagnostics.Subscribe(options.Events); } }); }