Enable bearer token in Swashbuckle (Swagger document)
Solution 1
Update
The issue detailed below is now resolved in Swashbuckle v5.5.0.
Issue
Just ran into the exact same issue. I think the root cause is this line in Swashbuckle's source code:
var key = encodeURIComponent($('#input_apiKey')[0].value);
This is where the value from the HTML input field goes through URL encoding turning the space into %20
. I'm planning to open an issue in the Swashbuckle repo on GitHub.
Workaround
Until that issue is resolved, here is a workaround based on replacing the above line using a Javascript file injected into the Swagger UI:
In the project where you have Swashbuckle installed, create a new folder and call it "Swagger".
-
In the new folder create a new Javascript file called "SwaggerUiCustomization.js" and put this script in it:
(function () { function addApiKeyAuthorization() { var key = $('#input_apiKey')[0].value; if (key && key.trim() != "") { var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization(swashbuckleConfig.apiKeyName, key, swashbuckleConfig.apiKeyIn); window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth); log("added key " + key); } } $('#input_apiKey').change(addApiKeyAuthorization); })();
In the Solution Explorer, choose the file and hit Alt+Enter to edit its Properties. In the Properties window change the file's Build Action to Embedded Resource.
In your SwaggerConfig.cs file add the following line inside the
EnableSwaggerUi()
code block:c.InjectJavaScript(thisAssembly, "<Project_Default_Namespace>.Swagger.SwaggerUiCustomization.js");
Be sure, of course, to replace<Project_Default_Namespace>
with your project's default namespace.Run your project and enter "Bearer " into the text box. When you invoke a controller action, you should get this exact same value - with a whitespace instead of
%20%
- on the server side.
Solution 2
In asp.net framework Web API , I was able to add the Bearer token on the UI and make it work properly by two different ways.
Way 1:
Adding an operation fitler. Create the following class :
public class AuthorizationHeaderParameterOperationFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
if (operation.parameters == null)
{
operation.parameters = new List<Parameter>();
}
operation.parameters.Add(new Parameter
{
name = "Authorization",
@in = "header",
description = "access token",
required = false,
type = "string",
@default = "Bearer "
});
}
}
and now in the SwaggerConfig.cs add the following:
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
// other settings
c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
})
.EnableSwaggerUi(c =>
{
// UI configurations
});
Way 2:
We can use the DocumentFilter as well to iterate all the operation and add the header, in the following one we skip the operation which actually takes username and password and gives the token for the first time:
public class SwaggerPathDescriptionFilter : IDocumentFilter
{
private string tokenUrlRoute = "Auth";
// the above is the action which returns token against valid credentials
private Dictionary<HeaderType, Parameter> headerDictionary;
private enum HeaderType { TokenAuth };
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
CreateHeadersDict();
var allOtherPaths = swaggerDoc.paths.Where(entry => !entry.Key.Contains(tokenUrlRoute)) //get the other paths which expose API resources and require token auth
.Select(entry => entry.Value)
.ToList();
foreach (var path in allOtherPaths)
{
AddHeadersToPath(path, HeaderType.TokenAuth);
}
}
/// <summary>
/// Adds the desired header descriptions to the path's parameter list
/// </summary>
private void AddHeadersToPath(PathItem path, params HeaderType[] headerTypes)
{
if (path.parameters != null)
{
path.parameters.Clear();
}
else
{
path.parameters = new List<Parameter>();
}
foreach (var type in headerTypes)
{
path.parameters.Add(headerDictionary[type]);
}
}
/// <summary>
/// Creates a dictionary containin all header descriptions
/// </summary>
private void CreateHeadersDict()
{
headerDictionary = new Dictionary<HeaderType, Parameter>();
headerDictionary.Add(HeaderType.TokenAuth, new Parameter() //token auth header
{
name = "Authorization",
@in = "header",
type = "string",
description = "Token Auth.",
required = true,
@default = "Bearer "
});
}
}
and then we need to regiter it in the SwaggerConfig.cs :
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
// other settings
c.DocumentFilter<SwaggerPathDescriptionFilter>();
})
.EnableSwaggerUi(c =>
{
// UI configurations
});
Now we will see the Token input for the headers in the swagger UI like:
Solution 3
Note: this example uses Json Web Tokens.
Your code can be set up so "Bearer" isn't required in the authorization string.
Code in WebApi project to retrieve token (see token = ... in the code segment below):
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
Swagger ApiKey:
c.ApiKey("Authorization")
.Description("Filling bearer token here")
.Name("Bearer")
.In("header");
Swagger Enable ApiKey Support:
c.EnableApiKeySupport("Authorization", "header");
Pasting token into Api_Key form element in Swagger UI:
How it looks in the request header in Swagger:
Solution 4
Update for OpenAPI 3, Swashbuckle.AspNetCore (6.7.1) full article address: https://codeburst.io/api-security-in-swagger-f2afff82fb8e The code to add JWT Bearer authorization to swagger. Add this in your Startup.cs in ConfigureServices method:
services.AddSwaggerGen(c =>
{
// configure SwaggerDoc and others
// add JWT Authentication
var securityScheme = new OpenApiSecurityScheme
{
Name = "JWT Authentication",
Description = "Enter JWT Bearer token **_only_**",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer", // must be lower case
BearerFormat = "JWT",
Reference = new OpenApiReference
{
Id = JwtBearerDefaults.AuthenticationScheme,
Type = ReferenceType.SecurityScheme
}
};
c.AddSecurityDefinition(securityScheme.Reference.Id, securityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{securityScheme, new string[] { }}
});
}
Bagusflyer
Updated on October 09, 2021Comments
-
Bagusflyer over 2 years
I created an asp.net webapi application which is using Individual Account Security so that the Bearer token is enabled by default. It's working fine so that I am able to test them in Postman without problem.
Here comes the question when I'm trying to integrate the Swagger UI by Swashbuckle. I installed the Swashbuckle by:
Install-Package Swashbuckle
Then change the SwaggerConfig.cs:
GlobalConfiguration.Configuration .EnableSwagger(c => { c.ApiKey("Token") .Description("Filling bearer token here") .Name("Authorization") .In("header"); } .EnableSwaggerUi(c => { c.EnableApiKeySupport("Authorization", "header"); };
Start my application and fill in the Bearer token:
But it doesn't work when I run the api request which need authorization. Here is the screenshot:
The bearer token is added to Authorization in header. But I still got error 401. I'm wondering if it's because the token is encoded (the SPACE is replaced by %20)? Any idea? Thanks.
By the way, I'm wondering how to add the /token in my Swagger document too so that I can get the token in Swagger UI.
-
Bagusflyer over 7 yearsI solved the issue by replace the index.html (it's actually the same as you did in the javascript). Thanks. But what is your suggestion on how to get the token? Because the
token
API is not in the Swagger document. I can of course to get the token by Postman, but it's not convinent. -
urig over 7 yearsI don't understand what you mean by "getting the token" and "token API". Can you explain?
-
Bagusflyer over 7 yearsThere is a
ConfigureAuth
method in Startup.Auth.cs which defile the endpoint, for example, we can define it as "/token" so that we can call this method to get token. But this api is not in swagger document. Anyway, I solved this already. Thanks anyway. -
richardb over 7 yearsStruggling to get the JavaScript injected - get an error " //localhost:44301/Swagger/ui/ext/SwaggerUiCustomization-js?_=1477558866989 404 (Not Found)"
-
richardb over 7 yearsOk thanks - great post and answer. Finally got it working. Saved my life.
-
urig over 7 years@richardb Swashbuckle v5.5.0 was just released 3 hours ago and has the fix built into it.
-
richardb over 7 yearsAh that explains things thanks - I was having no luck yesterday and just updated packages this morning. All great now and working like a dream.
-
Breeno almost 6 years@Zhou Hao How did you manage to resolve your issue of the "/token" endpoint not appearing in Swagger UI front end?
-
Breeno almost 6 years@Zhou Hao Never mind, found the solution. For benefit of others the solution is to create a custom class which extends DocumentFilter, give it the details of the operation and the schema, and inject it into the SwaggerConfig. Example can be found here github.com/domaindrivendev/Swashbuckle/issues/707
-
Admin over 4 yearsquick question, whats the work effort generally to add this into a project? I need to give estimate to manager, 5 hours or less? 10 hours? thinking it will be 2-3 hours most
-
Admin over 4 yearsI cannot run the command c.InjectJavascript in Net Core 2, how would I fix this?, SwaggerGenOptions does not contain definition for InjectJavascript
-
Admin over 4 yearsis there a way to store tokens after a computer restart or browser refresh?
-
Admin over 4 yearsis there a way to store tokens after a computer restart or browser refresh?
-
Jeremy Ray Brown over 4 yearsUsually the tokens are short lived and only requested to authorize a few requests. Can you provide more details for this need? A scenario your worried about?
-
Admin over 4 yearsahh, we keep refreshing browser, and keep having to type it in
-
Jeremy Ray Brown over 4 yearsYou can use the browser's session storage: w3schools.com/html/html5_webstorage.asp
-
Admin over 4 yearswhats the command line to store this? I was trying to figure out @jeremyraybrown
-
Jeremy Ray Brown over 4 yearsIn your SwaggerConfig.cs file, you call the EnableSwaggerUI method. You pass in a SwaggerUIConfig object. That object has a method InjectJavaScript. That is where you provide JavaScript to Swagger. Example:
c.InjectJavaScript(typeof(MySwaggerConfigClass)).Assembly, "Namespace.To.my-javascriptfile.js");
. You're JavaScript should wait for the DOM to be ready and then load a stored token into it. Put an event listener on the input that will save the token whenever its value changes. -
Jeremy Ray Brown over 4 yearsGoogle Swagger InjectJavaScript and you'll find additional help
-
Abdessamad Jadid over 3 yearsThanks , you saved my two days of searching, the second way work for me , i appreciate it
-
Ehsan Sajjad over 3 years@AbdessamadJadid cheers, glad to know it worked for you!