Search code examples
c#asp.net-coreasp.net-core-3.1microsoft-identity-platform

How to Add JwtBearer along with AddMicrosoftIdentityWebAppAuthentication


I am not sure I completely understood the changes for Microsoft.Identity.Web but I was following an article (given by Microsoft here) Where it described how to change in startup

 services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
     .AddAzureAD(options => Configuration.Bind("AzureAd", options));

to

services.AddMicrosoftIdentityWebAppAuthentication(Configuration);

while this looks good and easy I have a little more work because I have the following snippet in my existing code

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
   .AddAzureAD(options => this.configuration.Bind("AzureAd", options))
   .AddJwtBearer(options =>
   {
       //this code used to validate signing keys
       string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
       IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever());
       OpenIdConnectConfiguration openIdConfig = configurationManager.GetConfigurationAsync(CancellationToken.None).GetAwaiter().GetResult();
       var tenantId = this.configuration["TenantId"];
       var validIssuer = $"https://sts.windows.net/{tenantId}/";

       options.TokenValidationParameters = new TokenValidationParameters()
       {
           ValidIssuer = validIssuer,
           ValidAudience = this.configuration["ClientId"],
           IssuerSigningKeys = openIdConfig.SigningKeys,
       };
  });

To give you a little bit of context we have two variations with this application

  1. User Login and do some staff (here user will get Microsoft login dialog to login using his/her credential)
  2. Microsoft Azure calls our endpoint with some token and we need to validate that token.

The JWTvaliation section you see above is for the 2nd item where once we received a token we validate that token without login and UI workflow.

Question: The above code is working correctly. The only issue here is if we like to use Microsoft.Identity how should we use the second item (JWT) because services.AddAuthentication().AddAzureAD returns IAuthenticationBuilder which we use further to add AddJwtBearer, While services.AddMicrosoftIdentityWebAppAuthentication does not return IAuthenticationBuilder.


Solution

  • AddMicrosoftIdentityWebAppAuthentication is actually just a fancy way to do the following:

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(…)
    

    So it configures the default scheme to be the OIDC scheme and runs AddMicrosoftIdentityWebApp to configure whatever this ends up doing.

    Now, AddAuthentication can actually be called multiple times on the service collection. You just need to be careful not to reconfigure things incorrectly. The parameterless function does not do that, so it is a good way to access the IAuthenticationBuilder to further configure authentication.

    That means that you can change your code like this:

    // configure Microsoft Identity Web first
    // this also sets the default authentication to OIDC
    services.AddMicrosoftIdentityWebAppAuthentication(Configuration);
    
    // retrieve an authentication builder without changing the default
    services.AddAuthentication()
        // add JWT bearer now
       .AddJwtBearer(options =>
       {
           // …
       });