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

2

7

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:

  • In swagger UI I can click on "Authorize" button and get redirected to Azure for login.
  • The redirect successfully returns to swagger ui and I can see in the network tab that the token is retrieved from Azure by swagger ui.

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.

Lashing answered 21/12, 2021 at 23:3 Comment(4)
Were you able to figure out a proper solution for this? I'm having the same problem.Achondrite
I too seem to be running into this same issue and am also wondering if you ever found a proper solution? @mohammad-aliniaBookshelf
I'm going to give your question an up tick for the UPDATE you made with the solution, given there is no answer to up tick.Stipe
@Morph, that's not the way to do it as it adds the token to request headers for all endpoints, whether secured or not. check out my answer.Intentional
M
0

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

Macrobiotic answered 17/11, 2022 at 15:44 Comment(0)
I
0

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"}
                    }
                }
            };
        }
    }
}
Intentional answered 20/11, 2023 at 18:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.