Search code examples
azure-active-directoryswaggerauthorizationswagger-uiasp.net-core-5.0

How to correctly configure ASP.NET Core 5 Swagger to work with Azure A/D authorization code authentication?


I am upgrading my ASP.NET Core 5 Web API security from implicit to authorization code. The authentication is done using Azure A/D and I also need to allow Swagger docs to be used.

I have managed to make it work, but client_secret is useless in my case and I am wondering if I am doing something wrong. My configuration is as follows:

Azure A/D

  • Redirect URIs: https://localhost:44444/swagger/oauth2-redirect.html
  • API permissions: Microsoft Graph + custom role (access_as_user)
  • Tokens: Access tokens and ID tokens are unchecked

appsettings.json

"AzureAd": {
    "Instance": "https://login.microsoftonline.com",
    "ClientId": "xxxxxxxx-xxxxxxxxx",
    "TenantId": "xxxxxxxx-xxxxxxxxx"
},

Startup.cs

services.AddMicrosoftIdentityWebApiAuthentication(Configuration);

private static void AddSwagger(IServiceCollection services, AzureAdAuthOptions auth)
{
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "Foo API", Version = "v1", });
        AddSwaggerDocs_IncludeXmlComments(c);

        c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme()
        {
            Type = SecuritySchemeType.OAuth2,
            Flows = new OpenApiOAuthFlows()
            {
                AuthorizationCode = new OpenApiOAuthFlow()
                {
                    AuthorizationUrl = new Uri($"{auth.Instance}/{auth.TenantId}/oauth2/v2.0/authorize"),
                    TokenUrl = new Uri($"{auth.Instance}/{auth.TenantId}/oauth2/v2.0/token"),
                    Scopes = { { $"api://{auth.ClientId}/access_as_user", "Access as user" } }
                }
            }
        });

        c.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "oauth2"
                    }
                },
                new string[] { }
            }
        });
    });
}

Swagger

Scopes: only one, api://<guid>/access_as_user

If I authorize without the secret, it works correctly. However, if I provide the secret I receive the following error:

Auth ErrorError: Unauthorized, error: invalid_client, description: AADSTS700025: Client is public so neither 'client_assertion' nor 'client_secret' should be presented. Trace ID: dbb64172-2bbb-4392-8fc5-0ee71ab9c301 Correlation ID: 8c7edd8b-b6d0-435b-abeb-158b3278c3fe Timestamp: 2021-05-27 07:21:14Z

I thought the secret is required to make the authentication process more secure, but I do not seem to be able to use it. What am I doing wrong?


Double checked and allowPublicClient is false. I have switched from SPA to Web client, provided the secret, but I receive the following error:

Auth ErrorError: Bad Request, error: invalid_request, description: AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type. Trace ID: 6e11093f-319b-4d75-92b9-c6a39775a501 Correlation ID: afcd9152-ccd5-4588-ae75-0b829272d66d Timestamp: 2021-05-28 06:10:58Z

So, it seems that I am stuck with the SPA client when using Swagger UI.


Solution

  • This error indicates that your application is a public client application and not a confidential client application. Please see the differences between public client and confidential client applications.

    To solve this problem, you only need to modify the application manifest, change allowPublicClient to false.

    enter image description here

    Also, make sure you select Web when creating the application.

    enter image description here