Quarkus with Swagger UI apply global authorization - authentication

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!

Related

Create a personal access token (PAT) with OpenIddict

In OpenIddict, is it possible to have a second token endpoint that requires authorization and returns a long-lived token?
I'm converting a .Net Framework application to Core. As part of that I'm trying to swap the OAuth portions to OpenIddict. I've got standard authentication working using token endpoint just fine.
What I've been unable to do, or find an example of, is a second authenticated endpoint that generates a different token.
The purpose of the second endpoint is to provide a token similar to the PAT you get from GitHub or Azure DevOps
I was able to use this code to create a token on a second endpoint, but was not valid for authentication as I could not register it with OpenIddidct
var options = _oidcOptions.CurrentValue;
var descriptor = new SecurityTokenDescriptor
{
Claims = new Dictionary<string, object>
{
{ "sub", "your user id" },
{ "scope", "your scopes" },
},
EncryptingCredentials = options.DisableAccessTokenEncryption
? null
: options.EncryptionCredentials.First(),
Expires = null, // recommended to set this
IssuedAt = DateTime.UtcNow,
Issuer = "https://contoso.com/", // the URL your auth server is hosted on, with trailing slash
SigningCredentials = options.SigningCredentials.First(),
TokenType = OpenIddictConstants.JsonWebTokenTypes.AccessToken,
};
var accessToken = options.JsonWebTokenHandler.CreateToken(descriptor);

ServiceStack API aspnet core with Azure AD B2C returns 401 for request even with bearer token

I have a working ServiceStack API that authenticates against a AzureAD tenant. We are trying to move this to start using Azure B2C. The application is build with c# and runs on net 5.0. I've managed to change the configuration to use the 'correct' config. I'm then using Postman to get my access token from my tenant suing the authorization code flow.
However, when i make a request to the api, the response is always a 401 status code.
Where in the servicestack code can I put a break point to see why this failure is happening? I have tried multiple places in our AppHostConfigurator.cs/AppHost.cs files, but the break points doesn't appear to display why a 401 is being sent back as a response. I'm sure it's something related to wrong claims/roles expected etc, maybe the Azure ADB2C application being setup incorrectly, but obviously i need to know exactly so that i can resolve.
I'm setting up the authentication like this:
private static void ConfigureAuthentication(IAppHost host)
{
var authProviders = new List<IAuthProvider> {new NetCoreIdentityAuthProvider(host.AppSettings)};
if (host.AppSettings.GetAllKeys().Contains("AzureAdB2C"))
{
var debugMode = host.AppSettings.Get(nameof(HostConfig.DebugMode), false);
var azureSettings = host.AppSettings.Get<AzureAdB2COptions>("AzureAdB2C");
var jwt = azureSettings.GetB2CJWTProviderReader(debugMode);
jwt.PopulateSessionFilter = (session, payload, request) =>
{
if (session.Email == null && payload.ContainsKey("upn") && payload["upn"].Contains("#"))
session.Email = payload["upn"];
if (session.UserName == null && payload.ContainsKey("unique_name"))
session.UserName = payload["unique_name"];
};
authProviders.Add(jwt);
}
var auth = new AuthFeature(() => new AuthUserSession(), authProviders.ToArray())
{
HtmlRedirect = "/account/signin",
HtmlLogoutRedirect = "/account/signout",
IncludeAssignRoleServices = false,
IncludeRegistrationService = false
};
// remove default service authentication services
auth.ServiceRoutes.Remove(typeof(AuthenticateService));
host.Plugins.Add(auth);
}
We are using swagger as well to call the API (which works as expected). This question is more about that requests that are submitted with a bearer token.
thanks
Please refer to this existing answer for examples of how to validate why a 3rd Party JWT Token is invalid with ServiceStack's JWT Auth Provider.

OpenID Connect from Swagger UI with PKCE and Okta in .Net Core

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

Implement JwtBearer Authentication in NSwag SwaggerUi

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()).

How to configure Swagger in Web API 2 to POST OAuth2 authentication request?

I have recently started a Web API 2 project in Visual Studio 2012 using OWIN middleware to authenticate users with OAuth2. I incorporated token based authentication as outlined on this tutorial (Token Based Authentication). The authentication part works great. I have added some testing API methods and I wanted to hook up Swagger for my API documentation. I got that part working too, with the exception that the API calls from Swagger fail on authorization.
After research, I found Erik Dahl's post about how to hook up Swagger to OWIN middleware. After I configured my Swagger according to the post, I now see the authenticate buttons on the Swagger UI next to each API method. However, when trying to authenticate, the authentication within Swagger is done using a GET request. The authentication on the web API though requires it to be POST request. Is it possible to configure Swagger make the authentication request a POST? If not, should I allow my API to accept GET requests for token authentication? What would be the best approach to make this work?
Note: The request still hits my authentication logic, but the client_id and client_secret are not passed in a GET request, only in a POST request.
Here's my Swagger config:
httpConfig
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Sample API");
c.ApiKey("token")
.Description("API Key Authentication")
.Name("Bearer")
.In("header");
c.OAuth2("oauth2")
.AuthorizationUrl("/oauth/token")
.Flow("implicit")
.Description("OAuth2 authentication")
.Scopes(scopes =>
{
scopes.Add("sampleapi", "Sample API");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
})
.EnableSwaggerUi(c =>
{
c.EnableOAuth2Support(
clientId: "Sample_App",
clientSecret: "xxxxx",
realm: "test-realm",
appName: "Swagger UI");
});
And here's my OAuth config:
app.CreatePerOwinContext<ApiClientRepo>(ApiClientRepo.Create);
app.CreatePerOwinContext<MeetingRegistrantRepo>(MeetingRegistrantRepo.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:51071"),
RefreshTokenProvider = new SimpleRefreshTokenProvider()
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
No, I would not change the authentication method from POST to GET just to satisfy Swagger.
I found another article which should help you do what you want to do here : http://danielwertheim.se/use-identityserver-in-swaggerui-to-consume-a-secured-asp-net-webapi/
It wold be worth to try it that way. Don't forget that changing from POST to GET means you can no longer pass the parameters in the body of the request and you will instead have to do it in the URL of the request and that makes the whole thing insecure.
Yes, the ClientID and ClientSecret will still be part of the Authorization Header, but still do not open yourself up to stuff like this. Swagger should not dictate the architecture of your API so don't go there.