In my asp.net core 2.0 solution I want to add Azure AD authentication. With the Azure AD templates inside of VS 2017 you either get JWTBearer authentication-implementation or OpenIdConnect implementation. Open Id also has the reputation of being more secure than OAuth.
How can I use Open ID / JWT with the Swagger Ui, provided by NSwag?
My current workaround would be to allow both OAuth and Open Id, but I need to implement that myself and there is almost no documentation on the new 2.0 APIs. Its also less secure having two authentication workflows. Especially when one is less secure than the other.
Sample by renepape:
app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, settings =>
{
settings.GeneratorSettings.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT Token"));
settings.GeneratorSettings.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token",
new SwaggerSecurityScheme
{
Type = SwaggerSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = SwaggerSecurityApiKeyLocation.Header
}));
});
It works with UseSwaggerUi3 also.
I'm using NSwag v13.0.6, and adding JWT support with UseSwaggerUi3 in Startup.Configure (per the answer from #Der_Meister) no longer works.
Instead, I found I had to define the settings in the AddSwaggerDocument call in Startup.ConfigureServices:
// In the ConfigureServices method -- FWIW my app has this right after services.AddMvc()
services.AddSwaggerDocument(config => {
config.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token",
new OpenApiSecurityScheme {
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
}));
});
Note:
Add using NSwag.Generation.Processors.Security up top to resolve SecurityDefinitionAppender
All other types resolve with using NSwag
Then in Startup.Configure all you need is this:
app.UseSwaggerUi3();
Actually my working code in Startup.Configure differs slightly from the above because I use a custom swagger.json (it's a project requirement):
// Required for serving up a static, hand-rolled JSON file for Swagger doc.
app.UseStaticFiles();
// Specify the custom JSON location.
app.UseSwaggerUi3(settings => settings.DocumentPath = "/swagger/v1/swagger.json");
My custom swagger.json includes Bearer Authentication definitions. If you're letting NSwag generate the Swagger authentication definitions then your mileage may vary.
You can use config.AddSecurity as well and it seems a bit more designed for it:
services.AddSwaggerDocument(config => {
config.AddSecurity("JWT token", new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
});
config.PostProcess = (document) =>
{
document.Info.Version = "v1";
document.Info.Title = "MyRest-API";
document.Info.Description = "ASP.NET Core 3.1 MyRest-API";
};
});
However, both constructions resulted in an option to add a token in the Swagger UI, but didn't result in sending the Authorization header. When I added this line:
config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
it worked. The complete code in ConfigureServices:
services.AddSwaggerDocument(config => {
config.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT token"));
config.AddSecurity("JWT token", new OpenApiSecurityScheme
{
Type = OpenApiSecuritySchemeType.ApiKey,
Name = "Authorization",
Description = "Copy 'Bearer ' + valid JWT token into field",
In = OpenApiSecurityApiKeyLocation.Header
});
config.PostProcess = (document) =>
{
document.Info.Version = "v1";
document.Info.Title = "MyRest-API";
document.Info.Description = "ASP.NET Core 3.1 MyRest-API";
};
});
And in Configure
app.UseOpenApi();
app.UseSwaggerUi3();
The NSwag settings for the Swagger UI 2.x are very limited. First you need check how Swagger UI supports this and maybe you need to host Swagger UI yourself so that you can parametrize it more (and just generate the Swagger spec with NSwag).
In NSwag v11.7.2 you also have the option to use Swagger UI 3.x, maybe this is supported out-of-the-box in this version (UseSwaggerUi3()).
Related
I have an asp.net core web api. Say if i want to have two versions of the api such that, version 1 will require a bearer token and version 2 will not require the barer token.
Since the token configuration code resides in the startup.cs file, how do I have two startup.cs files to match my requirement above? i am not even sure if it is legal to have two startup.cs files targeting two different versions of the api because the code to configure versioning of an asp.net core api will also reside in the startup.cs file.
Let me know what options are available to achieve my requirement above.
My current startup.cs file with token authentication enabled look like this..
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AzureADSettings>(Configuration.GetSection("AzureAd"));
var azureADSettings = Configuration.GetSection("AzureAd").Get<AzureADSettings>();
var validAudience = new List<string>
{
azureADSettings.Audience
};
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.Authority = $"{azureADSettings.Instance}/{azureADSettings.TenantId}/";
o.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
//azureADSettings.Audience
ValidAudiences = new List<string>(validAudience)
};
});
}
The Authorize middleware applies that check if you do not explicitly a controller or action as Anonymous. Maybe what you can do is:
Put the [Anonymous] attribute on top of your controller(s).
Mark your v1 API end-points in your controller(s) as [Authorize].
Leave the v2 API end-points as-is.
This way, the v2 API end-points should work fine with users not having a bearer token but v1 API end-points should expect a valid bearer token.
After stepping around controller authorization in the debugger for the past 4 weeks, I finally decided to tackle OpenID Connect authentication in my Swashbuckle-supported .NetCore 5 API. I wish I hadn't, because I spent almost a day so far without a working solution.
Here is a brief recap.
Support for OpenID Connect in Swagger-UI is very recent. The only place where I found this information was in Helen's comment to this question. Swagger Ui 3.38.0 is only available in Swashbuckle 6.0.7.
Once upgraded to the latest Swashbuckle, I started to see a bunch of "discovered" authorization options in Swagger UI. Alas, PKCE does not appear to be in use, based on the error, even though I explicitly set it in Startup.cs:
.UseSwaggerUI(c => c.OAuthUsePkce());
Also, the ClientSecret there does not make sense, because PKCE is supposed to replace this (and I actually don't have a client secret).
My question, does anybody have OpenID Connect with PKCE and Okta working in Swagger UI?
Auth ErrorError, error: invalid_client, description: Browser requests to the token endpoint must use Proof Key for Code Exchange.
I've recently sitched from an implicit flow to code+pkce flow. I ran into the same issue. The key was to configure the token endopoint url. Swagger UI will still show you the client credentials input box, but you can leave this empty when authorizing.
var securityDefinition = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Scheme = "Bearer",
In = ParameterLocation.Header,
Name = "Authorization",
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(azureAdOptions.AuthorizeEndpoint),
TokenUrl = new Uri(azureAdOptions.TokenEndpoint),
Scopes = azureAdOptions.Applications["Api"].Scopes.ToDictionary(e => e.Value, e => e.Key)
}
}
};
c.AddSecurityDefinition(
"oauth2",
securityDefinition);
I obviously still have to enable pkce support on the SwaggerUiOptions
internal static void ConfigureUi(SwaggerUIOptions c, IConfiguration configuration, string apiName, string environmentName)
{
c.OAuthUsePkce();
}
I use Azure AD, here are the values I've used:
AuthorizationUrl: https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize
TokenUrl: https://login.microsoftonline.com/organizations/oauth2/v2.0/token
Scopes: custom-value
The commit below contains all the details of how it's implemented. It also contains a test sample.
Add support to PKCE for SwaggerUI & update OAuth2Integration sample
I have configured OpenAPI using #OpenAPIDefinition annotation to show the authorize (button) on the Swagger UI, but currently it has no functinality, when I try to authenticate it does nothing (no request is performed).
What I want to achieve is authenticate via the authorize button on the Swagger UI; then extract the token and pass it as a Authorization header on all endpoints.
How to configure and utilize the authorize functionality and then make it available globaly for all endpoints?
My application is secured using the HTTP with Bearer method.
Current config of the Swagger UI authentication
#OpenAPIDefinition(
info = #Info(
title = "My API",
version = "1.0.0"
),
components = #Components(
securitySchemes = {
#SecurityScheme(
securitySchemeName = "bearerAuth",
type = SecuritySchemeType.HTTP,
scheme = "bearer",
bearerFormat = "JWT"
),
#SecurityScheme(
securitySchemeName = "basic",
type = SecuritySchemeType.HTTP,
scheme = "basic"
)
}
),
security = {
#SecurityRequirement(name = "bearerAuth"),
#SecurityRequirement(name = "basic")
}
)
public class CustomApi extends Application { }
You need to also add the token url into the definition, so Swagger-UI knows how to retrieve the token and authenticate. I have a sample working here: https://github.com/radcortez/microprofile-samples/blob/042e4d349a09a8505b25b880dd4f3e0095b55369/services/book-api/src/main/java/com/microprofile/samples/services/book/BookApplication.java#L40-L55.
Please, let me know if that works for you. Cheers!
I am migrating a Web API that has Swagger documenation generated using Swashbuckle from .NET Framework to ASP.NET Core. In the new AspNetCore version I'm using Swashbuckle.AspNetCore v5.0.0-rc2.
This is an internal service and authentication uses an API key provided in a custom HTTP header. In the .NET Framework application, I configured Swashbuckle to enable my API key as follows:
c.ApiKey("apiKey")
.Description("My description")
.Name("MyHttpHeaderName")
.In("header);
and
c.EnableApiKeySupport("MyHtpHeaderName", "header);
How can I enable support for the same API key using Swashbuckle.AspNetCore v5.0.0-rc2?
Much of the information I've found by searching seems to relate to versions of Swashbuckle.AspNetCode prior to v5.0.0-rc2.
This answer is for v5.0.0-rc2 but only covers Bearer Authorization, and doesn't seem to relate to using a custom HTTP header: https://stackoverflow.com/a/57872872/13087
In Swashbuckle.AspNetCore, the authorization setup is all handled with the AddSecurityDefinition method.
In 4.x, you could set up an ApiKeyScheme that describes how to use an API key to authorize requests:
c.AddSecurityDefinition("ApiKey", new ApiKeyScheme()
{
Description = "My description",
Name = "MyHttpHeaderName",
In = "header",
});
Starting with 5.x, Swashbuckle.AspNetCore is no longer using its own models but instead relies on OpenAPI.NET. This means that the above security definition would look like this in 5.x:
c.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme()
{
Type = SecuritySchemeType.ApiKey,
In = ParameterLocation.Header,
Name = "MyHttpHeaderName",
Description = "My description",
});
Note that you will also have to set up security requirements to configure which security definition is required for what operations. In 5.x, the syntax for that will look like this:
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ApiKey" }
},
new string[] { }
}
});
You can read more about all this in the documentation on security definitions and requirements.
My SPA application (using Aurelia) calls my ASP.NET Core 2 Web API. I need to authenticate users with Google OIDC provider and also secure the Web API with the same method.
Currently I'm able to authenticate user on the client (SPA) side and retrieve id token and access token. With each API call I send the access token in the header.
Now I'm not sure how to handle the server side to validate the token and grant or deny the access to the API. I followed official docs how to add external login providers, but it seem to work only for server-side MVC applications.
Is there any easy way how to do this?
I think for instance IdentityServer4 can support this scenario, but it seems to me too complex for what I need to do. I don't need my own identity/authorization server after all.
Update:
Based on Miroslav Popovic answer, my configuration for ASP.NET Core 2.0 looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o =>
{
o.Authority = "https://accounts.google.com";
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "accounts.google.com",
ValidAudience = "xxxxxxxxxxxxx.apps.googleusercontent.com",
ValidateAudience = true,
ValidateIssuer = true
};
});
services.AddMvc();
}
And in Configure() I call app.UseAuthentication().
When using this setup I get failure message No SecurityTokenValidator available for token.
Update 2:
I made it work. The server configuration is correct. The problem was I was sending access_token to the API instead of id_token.
Since you already have the access token, it shouldn't be too hard to use it to add authentication. You would need something along these lines (not tested):
// Inside Startup.cs, ConfigureServices method
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(
options =>
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = "accounts.google.com",
ValidateAudience = false
};
options.MetadataAddress = "https://accounts.google.com/.well-known/openid-configuration";
options.TokenValidationParameters = tokenValidationParameters;
});
// Inside Startup.cs, Configure method
app.UseAuthentication(); // Before MVC middleware
app.UseMvc();
// And of course, on your controllers:
[Authorize]
public class MyApiController : Controller
This post from Paul Rowe might help some more, but note that it's written for ASP.NET Core 1.x and authentication APIs changed a bit in 2.0.
There is also a lot of info here on SO, like this question.