Setting Up Swagger (ASP.NET Core) Using the Authorization Headers (Bearer)

SwaggerUI with .NetCore 3.0 bearer token authorization

My implementation - excludes locks on non protected endpoints - with OperationFilter

internal static void SwaggerSetup(this IServiceCollection services, OpenApiInfo settings)
{
if (settings.Version != null)
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(settings.Version, settings);
c.OperationFilter<AddAuthHeaderOperationFilter>();
c.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
{
Description = "`Token only!!!` - without `Bearer_` prefix",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
In = ParameterLocation.Header,
Scheme = "bearer"
});
});
}
}

and the OperationFilter

private class AddAuthHeaderOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var isAuthorized = (context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
&& !context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()) //this excludes controllers with AllowAnonymous attribute in case base controller has Authorize attribute
|| (context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
&& !context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()); // this excludes methods with AllowAnonymous attribute

if (!isAuthorized) return;

operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });

var jwtbearerScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" }
};

operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement { [jwtbearerScheme] = new string []{} }
};
}
}

Reference https://thecodebuzz.com/jwt-authorize-swagger-using-ioperationfilter-asp-net-core/

just added the condition to exclude AllowAnonymous decorated methods

Result

Authorization Bearer token not being sent in request using Swagger in Asp.Net Core

The culprit

Configuration looks fine. It seems that the auth name you defined is the possible culprit.

services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "MyProject API",
Description = "MyProject"
});
options.DocInclusionPredicate((docName, description) => true);

// options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
// "bearerAuth" -> "oauth2"
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});

// Add this filter as well.
options.OperationFilter<SecurityRequirementsOperationFilter>();
});

You must use the definition name as "oauth2" unless you manually pass the securitySchemaName into the constructor. As a matter of fact the SecurityRequirementsOperationFilter uses the standard name by default. Just look at the securitySchemaName's default value.

public SecurityRequirementsOperationFilter(bool includeUnauthorizedAndForbiddenResponses = true, string securitySchemaName = "oauth2")
{
Func<IEnumerable<AuthorizeAttribute>, IEnumerable<string>> policySelector = (IEnumerable<AuthorizeAttribute> authAttributes) => authAttributes.Where((Func<AuthorizeAttribute, bool>)((AuthorizeAttribute a) => !string.IsNullOrEmpty(a.Policy))).Select((Func<AuthorizeAttribute, string>)((AuthorizeAttribute a) => a.Policy));
filter = new SecurityRequirementsOperationFilter<AuthorizeAttribute>(policySelector, includeUnauthorizedAndForbiddenResponses, securitySchemaName);
}

It works fine in my environment. Please try with this configuration and please don't forget to add the filter option.

Enabling authentication in swagger

I think Scheme should be "bearer" (lowercase b)

Scheme = "bearer",

JWT Authentication and Swagger with .NET Core 3.0

After some research, I eventually found the answer here

Before seeing this page, I knew that I should use AddSecurityRequirement after AddSecurityDefinition because of many samples, but it was a problem that the function parameters have changed on .NET Core 3.0.

By the way, the final answer is as below:

services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo {
Title = "My API",
Version = "v1"
});
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
In = ParameterLocation.Header,
Description = "Please insert JWT with Bearer into field",
Name = "Authorization",
Type = SecuritySchemeType.ApiKey
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
});

How can I display JWT bearer token roles required for endpoint in swagger UI for asp.net core 6 api endpoints

Assuming you have controllers or APIs decorated with Authorize attribute along with roles like

controller level authorize attribute

or

API level authorize attribute

although there is no separate place in swagger doc to show these information but we can enhance summary or description of a path in swagger doc to show this.

for that we have to add an custom OperationFilter like below

public class MyCustomOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
// get roles at method level first.
var roles = context.MethodInfo.
GetCustomAttributes(true)
.OfType<AuthorizeAttribute>()
.Select(a => a.Roles)
.Distinct()
.ToArray();

// we dont find roles at method level then check for controller level.
if(!roles.Any())
{
roles = context.MethodInfo.DeclaringType?
.GetCustomAttributes(true)
.OfType<AuthorizeAttribute>()
.Select(attr => attr.Roles)
.Distinct()
.ToArray();
}

if (roles.Any())
{
string rolesStr = string.Join(",", roles);
// we can choose summary or description as per our preference
operation.Description += $"<p> Required Roles ({rolesStr})</p>";
}
}
}

with these changes we can see the role info for each API like below

Role info shown in swagger ui

role info at api level

Currently this limited to show role info only from authorize attribute.

How do I set up Swashbuckle and Swagger UI to Authorize using Open ID Connect Discovery so it can supply the right Bearer token?

Since Swagger UI is using the web browser context to make the requests, I found it easier and way simpler to just provide a link at the top that will bring them to any API call that requires auth, and then also add a security requirement on all functions that require authorization.

This will work if your API automatically redirects and uses browser functionality to sign in, as I think most do. After the user signs in, all future HTTP requests from the Swagger UI will send the auth cookie just as it would for hitting the endpoints in the browser directly.

First, the Swagger config in Startup.cs, including a link to make signing in user-friendly:

services.AddSwaggerGen(c => {
OpenApiInfo apiInfo = new()
{
Title = "MyService",
Version = "v1",
Description = "<p>An API for working with ... "
+ "<p>If you get '<b>Failed to fetch</b>' below on an action that shows a padlock icon, this likely "
+ "means you are not <b>signed in</b>, so "
+ "<a target=\"_blank\" href=\"/api/v1/security/signIn\">sign in here</a>, then "
+ "your sign-in will take effect for any action below.",
};
c.SwaggerDoc("v1", apiInfo);

/* put other configuration here, such as c.IncludeXmlComments */

c.OperationFilter<MethodNeedsAuthorizationFilter>(); // puts auth UI on the right actions
});

In the example above, my endpoint /api/v1/security/signIn requires authorization; you can use any endpoint of yours that requires authorization.

Then here's the MethodNeedsAuthorizationFilter you need to enable showing the open padlock icon appropriately:

using Microsoft.AspNetCore.Authorization;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
using System.Collections.Generic;
using System.Linq;
namespace GeneralMills.TradePlannerService;
/// <summary>
/// Provides a method that applies Swagger UI security requirements to all controller actions that need authorization.
/// </summary>
public class MethodNeedsAuthorizationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation is null) throw new ArgumentNullException(nameof(operation));
if (context is null) throw new ArgumentNullException(nameof(context));

object[] methodAttributes = context.MethodInfo.GetCustomAttributes(true);

bool needsAuth =
methodAttributes.OfType<AuthorizeAttribute>().Any()
|| (context.MethodInfo.DeclaringType != null
&& context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
&& !methodAttributes.OfType<AllowAnonymousAttribute>().Any());

if (needsAuth)
{
OpenApiSecurityScheme scheme = new()
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ExampleName" },
Scheme = "ExampleName",
Name = "ExampleName",
In = ParameterLocation.Header,
};

operation.Security = new List<OpenApiSecurityRequirement>()
{
new () { {scheme, new List<string>() } }
};
}
}
}

This effectively circumvents Swagger UI's built-in authorization support, which I could not get working.

Bearer authentication in Swagger UI, when migrating to Swashbuckle.AspNetCore version 5

Got this working in the end by trial and error. This is the code that works for me:

c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description =
"JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 12345abcdef\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});

c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,

},
new List<string>()
}
});

I suspect there are probably properties being set there that don't actually need to be explicitly set, but the above is working for me.



Related Topics



Leave a reply



Submit