Mohammad Alinia
Mohammad Alinia

Reputation: 330

No auth header sent by swagger UI using Swashbuckle with OAuth code flow in .NET 6

I am trying to get OAuth code flow with PCKE to work with Swashbuckle (6.2.3) and swagger ui in .NET 6. There are a few things that happen successfully:

The problem is when I try to call the sample weather forecast API using swagger UI, no token is attached to the authorization header and it looks like this in the request:

authorization: Bearer undefined

And here is my code:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"));

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(options =>
{
    
    const string oAuth2 = "oauth2";
    options.AddSecurityDefinition(oAuth2, new OpenApiSecurityScheme
    {
        Type = SecuritySchemeType.OAuth2,
        Flows = new OpenApiOAuthFlows
        {
            AuthorizationCode = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri(builder.Configuration["AzureAdB2C:AuthorizationUrl"]),
                TokenUrl = new Uri(builder.Configuration["AzureAdB2C:TokenUrl"]),
                Scopes = {{"openid", "Sign users in"}, {"offline_access", "Maintain access to data you have given it access to"}}
            }
        },
        In = ParameterLocation.Header,
        BearerFormat = "JWT",
        Scheme = "bearer",
        Name = "authorization"
    });
    
    options.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Id = oAuth2,
                    Type = ReferenceType.SecurityScheme
                },
            }, new List<string> {"openid", "offline_access"}
        }
    });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(options =>
    {
        options.OAuthClientId(builder.Configuration["AzureAdB2C:ClientId"]);
        options.OAuthScopes("openid", "offline_access");
        options.OAuthUsePkce();
    });
}

app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

I'm not sure what I'm missing. Any ideas?

UPDATE: I have been able to get it to work with something like this:

        options.UseRequestInterceptor("(req) => { req.headers['Authorization'] = 'Bearer ' + window?.swaggerUIRedirectOauth2?.auth?.token?.id_token; return req; }");

But it doesn't look like a proper solution.

Upvotes: 7

Views: 1201

Answers (2)

KavehG
KavehG

Reputation: 323

You've defined the SecurityDefinition and SecurityRequirement but missed the part that specifies which endpoints need authorization. The token is attached only to requests called to secured endpoints.

You'll need to add

options.OperationFilter<MyOperationFilter>();

to your AddSwaggerGen( configuration, with the filter as something like this:

public class MyOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any())
        {
            operation.Security = new List<OpenApiSecurityRequirement>
            {
                //same security requirment defined in AddSecurityRequirement
                new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Id = oAuth2,
                                Type = ReferenceType.SecurityScheme
                            },
                        }, new List<string> {"openid", "offline_access"}
                    }
                }
            };
        }
    }
}

Upvotes: 0

fauri13
fauri13

Reputation: 1

You can specify in the OpenApiSecurityScheme to use the id_token instead the access_token that is the default by adding it to the Extensions:

Extensions =
{
  // Setting x-tokenName to id_token will send response_type=token id_token and the nonce to the auth provider.
  // x-tokenName also specifieds the name of the value from the response of the auth provider to use as bearer token.
  { "x-tokenName", new OpenApiString("id_token") }
}

Source: https://github.com/inouiw/SwaggerUIJsonWebToken/blob/master/Program.cs

Upvotes: 0

Related Questions