authenticationasp.net-core-webapiopenapi.net-9.0

How to configure ASP.NET Core 9 Web API so user can send a client secret as a request header when testing endpoints in the swagger documentation


I am upgrading a Web API project to .NET 9, and using Swashbuckle 9 to display the Swagger documentation page. I would like users of the documentation page to enter a client secret (just a string) when testing any of the endpoints, and for the client secret to be sent over as a custom header in each request.

Inspired by https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/customize-openapi?view=aspnetcore-9.0#use-document-transformers, my documentation page is allowing users to enter the client secret, but it is not being sent over in the requests.

My program.cs looks like this at the moment:

var builder = WebApplication.CreateBuilder(args);

// ...

builder.Services.AddOpenApi(o =>
{
    o.AddDocumentTransformer((document, context, cancellationToken) =>
    {
        document.Components ??= new OpenApiComponents();
        document.Components.SecuritySchemes = new Dictionary<string, OpenApiSecurityScheme>
        {
            ["Client-Secret-1"] = new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.Http, // tried ApiKey as well
                Name = "Client-Secret-1",
                Scheme = "bearer",
                In = ParameterLocation.Header
            }
        };
        return Task.CompletedTask;
    });
});

var app = builder.Build();

// ...

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/openapi/v1.json", "MyProjectName");
    });
}

// ...

app.Run();

Can anyone provide a clue as to why the client secret is collected by the page but not sent over with the request? I am also unsure if Scheme = "bearer" is the correct setting since this is a client secret that is validated via a custom ServiceFilter on the controller and cannot have the word "bearer" in its value.


Solution

  • I eventually decided to switch the UI tool from Swashbuckle to Scalar and saw that a bearer token was actually being sent in the request header using my original code. That was encouraging, so I changed the Type to ApiKey and removed the Scheme altogether and that did the trick!

    I have gone back to Swashbuckle with the exact same generated document from OpenAPI but it still doesn't send over anything! Maybe it is user error, so I am listing my steps with the Swashbuckle UI:

    Its a shame I wasted so many hours and it was the Swashbuckle UI all along. Anyway, here are the relevant bits of my program.cs to make it work with Scalar UI.

    var builder = WebApplication.CreateBuilder(args);
    
    // ...
    
    builder.Services.AddOpenApi(o =>
    {
        o.AddDocumentTransformer((document, context, cancellationToken) =>
        {
            document.Components ??= new OpenApiComponents();
            document.Components.SecuritySchemes = new Dictionary<string, OpenApiSecurityScheme>
            {
                ["Client-Secret-1"] = new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.ApiKey,
                    Name = "Client-Secret-1",
                    In = ParameterLocation.Header
                }
            };
            return Task.CompletedTask;
        });
    });
    
    var app = builder.Build();
    
    // ...
    
    if (app.Environment.IsDevelopment())
    {
        app.MapOpenApi();
        app.MapScalarApiReference();
    }
    
    // ...
    
    app.Run();