Quote of the Day

more Quotes

Categories

Get notified of new posts

Buy me coffee

  • Home>
  • security>

Migrating from Microsoft.AspNetCore.Authentication.AzureAD to Microsoft Identity Web authentication library to integrate with Azure AD.

I recently had a chance to clean up some of the deprecated libraries I used for validating a JWT access token or obtain one via the client-credentials flow or the on-behalf-of flow. The libraries I used were under the Microsoft.AspNetCore.Authentication.AzureAD packages. Per the document, since ASP.NET core 5.0, users should use the Microsoft.Identity.Web package to integrate with Azure AD and Azure ADB2C.

Before, to validate a token, I used the Microsoft.AspNetCore.Authentication.AzureAD package along with the Microsoft.AspNetCore.Authentication.JwtBearer package. I explicitly specified the token validation parameters to validate a token.

 
        public static IServiceCollection AddSecurity(this IServiceCollection services,
                                                                                         IConfiguration configuration)
        {
            var aadOptionSection = configuration.GetSection("WebAPIToSecure");

            AzureADOptions aadOptions = aadOptionSection.Get<AzureADOptions>();
            services.AddCache();
            services.AddSession();
            services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
                .AddAzureADBearer(options =>
                {
                    aadOptionSection.Bind(options);
                });
            services.Configure<AzureADOptions>(aadOptionSection);
            services.Configure<ConfidentialClientApplicationOptions>(aadOptionSection);
            services.AddScoped<ITokenAcquisition, TokenAcquisition>();
            services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
            {
                // This is an Azure AD v2.0 Web API 
                options.Authority += "/v2.0";
                options.TokenValidationParameters.ValidateTokenReplay = true;

                options.TokenValidationParameters.ValidIssuer = string.Format(@"https://sts.windows.net/{0}/", aadOptions.TenantId);
                options.TokenValidationParameters.ValidateIssuer = true;
                options.TokenValidationParameters.ValidateAudience = true;
                options.TokenValidationParameters.ValidateLifetime = true;
                options.TokenValidationParameters.ValidAudiences = new string[] { options.Audience, $"api://{options.Audience}" };
           
                options.Events = new JwtBearerEvents();


                options.Events = JwtBearerMiddlewareDiagnostics.Subscribe(options.Events);
            });

            return services;
        }

When switching to the Microsoft.Identity.Web package, I learned that the library performs much of the validation automatically by default. Per the document, the library checks for the following:

– Audience: The token is targeted for the web API.

– Sub: It was issued for an app that’s allowed to call the web API.

– Issuer: It was issued by a trusted security token service (STS).

– Expiry: Its lifetime is in range.

– Signature: It wasn’t tampered with.

Token Validation

As such, I was able to remove much of the configs, as demonstrated in the below code snippet.

public static IServiceCollection AddSecurity(this IServiceCollection services,
                                                                                         IConfiguration configuration)
        {
            services.Configure<ConfidentialClientApplicationOptions>(aadOptionSection);
            services.AddScoped<ITokenAcquisition, TokenAcquisition>();
            services.AddMicrosoftIdentityWebApiAuthentication(configuration, configSectionName: "WebAPIToSecure");

            return services;
        }

Note that you still can customize the token validation parameters if necessary, as per the document.

The web API in turn needs to access another downstream web API, which also requires an access token. Previously, I explicitly setup ConfidentialClientApplicationOptions and ITokenAcquisition. However, with Microsoft.Identity.Web package, the setup is more fluent, as shown in the below code snippet.

    services.AddMicrosoftIdentityWebApiAuthentication(_configuration, configSectionName: "WebAPIToSecure")
              .EnableTokenAcquisitionToCallDownstreamApi()
              .AddDownstreamWebApi("DownstreamAPI", _configuration.GetSection(DownstreamAPI))
              .AddInMemoryTokenCaches();

Below code snippet shows the relevant configs in app settings.

    "WebAPIToSecure": {
      "Instance": "https://login.microsoftonline.com/",
      "ClientId": "********-****-****-****-************",
      "ClientSecret": "secret",
      "TenantId": "********-****-****-****-************"
    }


    "DownstreamAPI": {
        "BaseUrl": "https://localhost:44307/api",
        "ClientId": "********-****-****-****-************",
    }

Note that you don’t even need to specify configSectionName if you name the section as “AzureAD” in app settings, as that is the default. In my project, I named the section differently, so I specified the parameter.

Below code snippets show how I use the ITokenAcquisition to obtain an access token via the on-behalf-of flow for the web API (WebAPIToSecure) to access the downstream API (DownstreamAPI).

var downstreamAPIClientId = configuration.GetSection("DownstreamAPI:ClientId").Get < string > ();
          var authenticationResult = await tokenAcquisition.GetAuthenticationResultForUserAsync(new string[] {
            $ "api://{downstreamAPIClientId}/.default"
          });
          var accessToken = authenticationResult.AccessToken;

In the above snippets, I call the method GetAuthenticationResultForUserAsync as it is the one for the on-behalf-of flow. The ITokenAcquisition interface also exposes the other method, GetAccessTokenForAppAsync, which is for the client-credentials flow. To learn more, check out the document.

References

Authentication: AzureAD.UI and AzureADB2C.UI APIs and packages marked obsolete

Microsoft.AspNetCore.Authentication.Jwt.Bearer

Token Validation

A web API that calls web APIs: Acquire a token for the app

No comments yet