'Invalid token' when using webapi thru Swagger authenticated by Azure AD

Viewed 1287

I try to use AAD authentification on my WebApi (dotnet core 3.1) from swagger (Swashbuckle) client. In my Startup class, I've configured like follow:

// Configure authentication
services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
        .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

my settings for AzureAd:

"AzureAd": {
 "Instance": "https://login.microsoftonline.com/",
 "ClientId": "xxxx-xxxxx1b",
 "Domain": "myoffice.onmicrosoft.com",
 "TenantId": "xxxxx-xxxxa5",
 "Scope": "api://xxxxxxxx-abc3cff48f1b/Full.Access",
 "ScopeDescription": "Full Access"
},

...

services.AddSwaggerGen(c =>
{
   c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
      {
          Type = SecuritySchemeType.OAuth2,
          In = ParameterLocation.Header,
          Flows = new OpenApiOAuthFlows()
          {
               Implicit = new OpenApiOAuthFlow
               {
                   TokenUrl = new Uri($"Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/token"),
                   AuthorizationUrl = new Uri($"{Configuration["AzureAd:Instance"]}/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0/authorize"),
                   Scopes =
                   {
                        {
                            Configuration["AzureAd:Scope"],Configuration["AzureAd:ScopeDescription"]
                        }
                   }
               }
           }
      });
  c.AddSecurityRequirement(new OpenApiSecurityRequirement
  {
      {
           new OpenApiSecurityScheme
           {
               Reference = new OpenApiReference
               {
                   Type = ReferenceType.SecurityScheme,
                   Id = "Bearer"
               }
            },
            Array.Empty<string>()
            }
        });
    });

And in my Configure method:

 app.UseSwaggerUI(c =>
 {
    c.RoutePrefix = string.Empty;
    c.SwaggerEndpoint($"/swagger/{ApiVersion}/swagger.json", ApiName);
    c.OAuthClientId(Configuration["AzureAd:ClientId"]);
    c.OAuthScopeSeparator(" ");
 });

Swagger corectly log to AAD using my credential and when I use a route protected by [Authorize] the token is correcly sent to the API by I receive a 401 error with the following message:

www-authenticate: Bearer error="invalid_token"error_description="The issuer 'https://login.microsoftonline.com/{tenantid}/v2.0' is invalid"

The url https://login.microsoftonline.com/{tenantid}/v2.0 is in the token in the iss section.

What is wrong?

1 Answers

According to your error and your code, you do not tell your application the ValidIssuer. So you get the error. Please add the following code in the method ConfigureServices of startup.cs file

services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
        
                    ValidIssuers = new[] {
                     
                    },                    
            });

For example

  • Configure Azure AD for your web API. For more details, please refer to the document

    a. Create Azure AD web api application

    b. Expose API enter image description here

    c. Configure code

    1. config file
    "AzureAd": {
     "Instance": "https://login.microsoftonline.com/",
     "ClientId": "[Client_id-of-web-api-eg-2ec40e65-ba09-4853-bcde-bcb60029e596]",  
     "TenantId": "<your tenant id>"
    },
    
    1. Add following code in the Stratup.cs
     services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
                 .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
    
             services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
             {
                 options.Authority += "/v2.0";
    
    
                 options.TokenValidationParameters = new TokenValidationParameters
                 {
                    /**
                     *  with the single-tenant application, you can configure your issuers 
                     *  with the multiple-tenant application, please set ValidateIssuer as false to disable issuer validation 
                    */
                     ValidIssuers = new[] {
                       $"https://sts.windows.net/{Configuration["AzureAD:TenantId"]}/",
                       $"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/v2.0"
    
                     },
    
                     ValidAudiences = new[]
                     {
                            options.Audience,
                            $"api://{options.Audience}"
                     }
    
                 };
    
             });
    
  • Configure swagger. For more details, please refer to the blog.

    a. Create Azure Web application

    enter image description here enter image description here enter image description here

    b. Configure API permissions. Regarding how to configure, you can refer to the document

    c. code

    1. Install SDK

       <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
      
    2. config file

       "Swagger": {
           "ClientId": ""
        },
      
    3. Add the following code to Startup.cs in the ConfigureServices method:

       services.AddSwaggerGen(o =>
           {
               // Setup our document's basic info
               o.SwaggerDoc("v1", new OpenApiInfo
               {
                   Title = "Protected Api",
                   Version = "1.0"
               });
      
               // Define that the API requires OAuth 2 tokens
               o.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
               {
                   Type = SecuritySchemeType.OAuth2,
      
                   Flows = new OpenApiOAuthFlows
                   {
                       Implicit = new OpenApiOAuthFlow
                       {
                           Scopes = new Dictionary<string, string>
                           {
                               { "api://872ebcec-c24a-4399-835a-201cdaf7d68b/user_impersonation","allow user to access api"}
                           },
                           AuthorizationUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/authorize"),
                           TokenUrl = new Uri($"https://login.microsoftonline.com/{Configuration["AzureAD:TenantId"]}/oauth2/v2.0/token")
                       }
                   }
               });
      
               o.AddSecurityRequirement(new OpenApiSecurityRequirement{
               {
                   new OpenApiSecurityScheme{
                       Reference = new OpenApiReference{
                           Id = "oauth2",
                           Type = ReferenceType.SecurityScheme
                       }
                   },new List<string>()
                   }
               });
      
           });
      
    4. Add the following code to the Configure method:

       app.UseSwagger();
           app.UseSwaggerUI(c =>
           {
               c.OAuthClientId(Configuration["Swagger:ClientId"]);
               c.OAuthScopeSeparator(" ");
               c.OAuthAppName("Protected Api");
      
               c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
           });
      
  • Test enter image description here

Related