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.
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
I just upgraded my project from Swashbuckle 5.6.3 to 6.0.7. I have made no code changes, but now when attempting to use the Swagger page to test the API, the URL generated by Swagger is not using https even though the page is loaded through https and all the documentation I can find says that it should infer the scheme based on the URL used to load the Swagger page.
Here is the configuration code:
services.AddSwaggerGen(c => {
c.SwaggerDoc(apiSettings.Version, new OpenApiInfo { Title = apiSettings.Name, Version = apiSettings.Version });
c.CustomSchemaIds(type => type.FullName);
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme {
Description = "JWT Authorization header using the Bearer scheme.",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "bearer",
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{ new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new List<string>() }
});
});
and:
app.UseSwagger();
app.UseSwaggerUI(c => {
c.SwaggerEndpoint($"/swagger/{apiSettings.Version}/swagger.json", $"{apiSettings.Name} {apiSettings.Version}");
});
Is there a new configuration setting to specify the scheme now?
In version 6.0.7, you can change this behavior with the MapSwagger extension method.
app.UseEndpoints(endpoints =>
{
...
endpoints.MapSwagger($"/swagger/{apiSettings.Version}/swagger.json", o =>
{
o.PreSerializeFilters.Add((swagger, httpReq) =>
{
swagger.Servers.Clear();
});
});
});
In the end, this is the final code that worked for me.
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapSwagger("/swagger/{documentName}/swagger.json", options => {
options.PreSerializeFilters.Add((swagger, httpRequest) => { });
});
});
I am developing some Web API with .NET Core 3.0 and want to integrate it with SwashBuckle.Swagger.
It is working fine, but when I add JWT authentication, it does not work as I expect.
To do that, I added the code below:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My Web API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
After adding AddSecurityDefinition function, I can see the Authorize button and when I click it, I see the form below:
Then I type Bearer WhatEverApiKeyIsfgdgdgdg845734987fgdhgiher635kjh. After doing it, I expect to see authorization: Bearer WhatEverApiKeyIsfgdgdgdg845734987fgdhgiher635kjh in the request's header when I send a request to the Web API from Swagger, but authorization is not added to the request header. I am using SwashBuckle.Swagger(5.0.0-rc3). Please note there are many samples which work fine on .NET Core 2.0, but Swashbuckle swagger functions has changed on the latest version so I cannot use those samples.
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[] { }
}
});
});
If you are using Swagger 3.0 then it has build-in support for JWT authentication.
You need to use ParameterLocation.Header, SecuritySchemeType.Http, bearer, and JWT in OpenApiSecurityScheme as shown below.
After this, you wouldn't need to specify token in Bearer {token} format. Only specify the token and the security scheme will automatically apply it in the header.
// Bearer token authentication
OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme()
{
Name = "Bearer",
BearerFormat = "JWT",
Scheme = "bearer",
Description = "Specify the authorization token.",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
};
c.AddSecurityDefinition("jwt_auth", securityDefinition);
// Make sure swagger UI requires a Bearer token specified
OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme()
{
Reference = new OpenApiReference()
{
Id = "jwt_auth",
Type = ReferenceType.SecurityScheme
}
};
OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement()
{
{securityScheme, new string[] { }},
};
c.AddSecurityRequirement(securityRequirements);
In the accepted answer, "Bearer " is required to be written before the actual token.
A similar approach in which typing "Bearer " can be skipped is the following:
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Example API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
In = ParameterLocation.Header,
Scheme = "bearer",
Description = "Please insert JWT token into field"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
Here, only pasting the JWT token is required for this to work.
Here's a solution updated for Swashbuckle.AspNetCore 5.3.2, integrated with IdentityServer4, with an API secured using a Bearer token.
In ConfigureServices() method:
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
options.AddSecurityDefinition("Bearer", SecuritySchemes.BearerScheme(Configuration));
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{ SecuritySchemes.OAuthScheme, new List<string>() }
});
});
In Configure() method:
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/My.Api/swagger/v1/swagger.json", "My API V1");
options.OAuthClientId(Clients.TestClient);
options.OAuthAppName("My Api - Swagger");
options.OAuthClientSecret(Configuration["TestClientSecret"]);
});
internal static class SecuritySchemes
{
public static OpenApiSecurityScheme BearerScheme(IConfiguration config) => new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Description = "Standard authorisation using the Bearer scheme. Example: \"bearer {token}\"",
In = ParameterLocation.Header,
Name = "Authorization",
Scheme = "Bearer",
OpenIdConnectUrl = new System.Uri($"{config["TokenServerUrl"]}.well-known/openid-configuration"),
BearerFormat = "JWT",
Flows = new OpenApiOAuthFlows
{
Password = new OpenApiOAuthFlow
{
AuthorizationUrl = new System.Uri($"{config["TokenServerUrl"]}connect/authorize"),
Scopes = new Dictionary<string, string>
{
{ Scopes.Api, "My Api" }
},
TokenUrl = new System.Uri($"{config["TokenServerUrl"]}connect/token")
}
}
};
public static OpenApiSecurityScheme OAuthScheme => new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
};
}
If anyone is using NSwag and has landed here after searching the solution, here is the link from the official documentation.
NSwag Enable JWT authentication
PS: I know the original question was for SwashBuckle, but Google shows this link first when searching for NSwag as well.
If you don't want to add a token manually and you want the scopes to be selectable along with passing a clientId to the identity server you can add something like this.
I have used implicit flow, but you can configure any flow using the following mechanism:
options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme()
{
Flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri("http://localhost"),
TokenUrl = new Uri("http://localhost"),
Scopes = new Dictionary<string, string>
{
{ "Foundation API", "FoundationApi" }
}
}
},
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.OAuth2
});
The output will be like this:
In Accept answer you have to manually append "bearer" with token, this will create new issues, Swagger can append "bearer" with token watch this following link
JWT Authentication and Swagger with .NET Core 3 and 5 YouTube video
I have basic Api that accepts a default header value for my-api-key and the corresponding value.
I'm trying to get the Swagger UI to allow me to enter the header one time for Authorization and have the key/value passed along with every request.
So far, I've only been successful with explicitly adding the header as a parameter to every endpoint, but that isn't ideal.
Relevant code snippets:
services.AddApiVersioning(
options =>
{
// reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
options.ReportApiVersions = true;
});
services.AddVersionedApiExplorer(
options =>
{
// add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
// note: the specified format code will format the version as "'v'major[.minor][-status]"
options.GroupNameFormat = "'v'VVV";
// note: this option is only necessary when versioning by url segment. the SubstitutionFormat
// can also be used to control the format of the API version in route templates
options.SubstituteApiVersionInUrl = true;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Api", Version = "v1" });
c.SwaggerDoc("v2", new OpenApiInfo { Title = "Api", Version = "v2" });
// this isn't ideal as I have to fill in the Api Key on ever request
//c.OperationFilter<ApiKeySwaggerFilter>();
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{
Type = SecuritySchemeType.ApiKey,
Name = "my-api-key",
In = ParameterLocation.Header
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ new OpenApiSecurityScheme()
{
// Type = SecuritySchemeType.ApiKey,
Name = ""
//In = ParameterLocation.Header
//Reference = new OpenApiReference()
//{
// Id = "myToken",
// Type = ReferenceType.SecurityScheme
//},
}, new string[] { }
}
});
});
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Api v1");
c.SwaggerEndpoint("/swagger/v2/swagger.json", "Api v2");
});
Corresponding image of where I'm at:
Corresponding minimal spike: https://github.com/aherrick/SwaggerSample
I feel this is close, but how do I get the Api Header to get passed on every request, without having to force the user to fill in parameter on every method request.
Figured it out with the following section update:
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme
{
Description = "Enter your Api Key below:",
Name = "my-api-key",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "ApiKey"
},
},
new List<string>()
}
});
Pre-fill the Bearer token with a JWT returned from service and set and set Authorized to True, so the user does not have to manually click the authorize button and enter the token. But UI just doesn't send the property authorization.
Swagger UI
ui = SwaggerUIBundle({
url: "https://localhost:44318/swagger/v1/swagger.json",
onComplete: function () {
// Default API key
ui.preauthorizeApiKey("bearer", token);
}
})
Security Scheme
c.AddSecurityDefinition("bearer", new OpenApiSecurityScheme {
Description = x.SwaggerAuthorization_desc,
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "bearer"
}
},
new string[] {}
}
});
SwaggerUI: 5.0.0
OpenAPI: 3.0.1
SecuritySchemes: Bearer