Skip to content

inouiw/SwaggerUIJsonWebToken

Repository files navigation

Swagger-UI example using ASP.NET Core (.NET 6) minimal web API project with implicit OAuth flow JSON Web Token authentication

Goals

  1. Show how to request an id_token with the implicit auth flow from swagger-ui.
  2. Show how to validate a JWT in ASP.NET Core with a few lines of code and without needing IdentityServer or database tables.
  3. Show how to use a self-build swagger-ui artifacts that allow debugging swagger-ui JavaScript sources.

How to run

Clone the repository
git clone https://github.com/inouiw/SwaggerUIJsonWebToken.git

Open the solution with VsCode
code SwaggerUIJsonWebToken

Press F5 to debug

About the code

File Program.cs

  • Configures a ASP.NET minimal web api application.
  • Adds the middleware: Swagger, SwaggerUI, Authentication with JwtBearer, and other.
  • Verifies the id-token Signature, Issuer, Audience and ExpirationTime using the Microsoft.AspNetCore.Authentication.JwtBearer package. Note that the public key is cached and refreshed, if expired, by the middleware.
  • Adds an endpoint that, when called, returns the authentication status of the caller and the claims in the Bearer JWT. The claims are accessible in context.User.Claims.
  • Adds a route which loads swagger-ui artifacts from wwwroot/swagger instead of using the sources from the middleware.

File wwwroot/swagger-extensions/my-index.html

  • Contains the swagger-ui index.html modified to load the default export of my-swagger-ui-plugins.js and assigns it to the configObject.plugins array.

    File wwwroot/swagger-extensions/my-swagger-ui-plugins.js

  • Contains wrapActions that add custom behavior to the swagger-ui actions authPopup and authorizeOauth2WithPersistOption. The actions modify the token endpoint URL to include response_type=token id_token and nonce=<random value> and verify the returned nonce value.

Folder wwwroot/swagger

  • Contains a build of wagger-ui-4.12.0 with sourcemaps.

Details

Swagger UI does not support the OAuth 2.0 implicit grant flow with id_token. Swagger supports OAuth2 implicit flow but it always sets response_type=token in the request (see oauth2-authorize.js), however response_type=token id_token is required.

As alternative to OAuth, swagger-ui also supports OpenID Connect (OIDC), however not the implicit flow but only the authorization code flow. In that case the response from the authorization provider with the code is redirected to the server to a oauth2-redirect.html file, then the client secret is sent to the browser together with the code. For me this seems wrong because the client secret should stay on the server. Also the implicit id-token flow has advantages.

However, swagger-ui offers very nice ways to extend and customize almost everything. So, I made use of wrapActions that are just JavaScript methods which get called any time when a call to the wrapped action is made. (See Plugin system overview)
I created two wrapActions, one to modify the response_type and set a random nonce and one to validate the nonce value. See wwwroot/swagger-extensions/my-swagger-ui-plugins.js

What is the Implicit flow with id-token?

With the implicit flow with id-token the client receives the claims reply as JWT/id-token. The client can use the claims only in the single-page-app or it can use the id-token to authenticate (see why-not-authorizie) with the server. To authenticate with the server the client app sends the id-token in the authorization header. The server can verify if the claims in the id-token can be trusted by verifying the token signature using a public key from the .well-known/openid-configuration.
Also see what-are-the-advantages-of-the-implicit-flow

What is the authorization code flow?

With the authorization code flow the client requests a authorization code which is then send to the server. The server uses the code and the client secret to request a access token and refresh token. Then the server can use the access token to get the user claims. The server will have to set some cookie or generate a JWT for the client to know that it is now authenticated. An advantage, if you generate the JWT yourself, is that you can add custom claims, although the token should not be too large.

What are the advantages of the implicit flow?

As can be seen in the above description, with the implicit flow, the id-token can be used by the client to authenticate. With the authorization code flow a server request is needed and the code cannot be used by the client to authenticate because it expires soon.

When to use the OAuth2 authorizaiton framework only for authenticating not for authorizing the user?

With OAuth authorization the user gives another application access to scopes. For example the user can authorize your app to access the scope email address or calendar by requesting a token with these scopes. In the swagger authorize pop-up it is described as follows: "Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes."

You can use OAuth for authorization if you want to store which user has access to which resource with the OAuth provider. However if you have hundreds of resources this becomes difficult to manage. So then you may decide to just store roles with the authorization provider. But if the authorization provider only provides roles then the decision if the role is authorized to access a resource is still in your application. So you are not really using OAuth for authorization.

Since it is not always possible or easy to store custom claims with a fee OAuth provider, you can also just use the scope email that is offered by eg. Google to authenticate the user. To decide if the user is authorized for a resource, you can extend your data model, that probalbly already contains a user entity, with a roles or claims entity. Then, in the authorization middleware, you can use the authenticated users email claim and the roles/claims in the database to decide if the user is authorized to access the requested resource.

Some notes

To intercept the HTTPS Traffic, I use the cross-platform open source HTTP Toolkit.

If you get the error 400: redirect_uri_mismatch from the authentication provider, as google, then first restart the server and check again, if the error appears again, you will likely need to add your URIs as https://localhost:7253/swagger/oauth2-redirect.html to the "Authorized redirect URIs". For google you can set it in the Google Cloud Console. In this application it is never redirected to the redirect URL because the client receives the response from the authentication provider but the redirect link is not followed because it is not needed.

The main file Program.cs contains a client-id that I created. You can use Google Could Console to generate your own google client-id.

To read more about the implicit OAuth flow you may start at the google documentation for OAuth 2.0 for Client-side Web Applications and OpenID Connect, or the Microsoft Azure Implicit Grant Flow Docs.

Debugging

After starting the solution and opening the browser developer tools, you should be able to see SwaggerUIBundle in the Sources tab. You can browse the Swagger-UI source code and set breakpoints.

Source Maps Debugging Screenshot

Keywords

OAuth, Delegated authentication, authorization server, access token, access_token, scopes (openid, email, profile), resource owner, clientid, client_id, clientsecret, bearer, credentials, secret, OAuth2, nonce, identity, client-id, oauth2RedirectUrl

Swagger Plugin API, swagger-ui, Swashbuckle, wrapActions example, x-tokenName

ASP.NET Core 6 minimal Web API, validate JwtBearer, UseSwaggerUI (OAuthClientId, IndexStream, SwaggerEndpoint, RoutePrefix), UseSwagger, AddSwaggerGen (OpenApiOAuthFlows, SwaggerDoc, AddSecurityDefinition, SecuritySchemeType, OpenApiOAuthFlows, OpenApiSecurityRequirement, OpenApiReference), AddAuthentication(AddJwtBearer, MetadataAddress, TokenValidationParameters), AddEndpointsApiExplorer, UseAuthentication

JavaScript, extension, plugin, debug, chrome, sourcemaps, swagger-ui-bundle.js, swagger-ui-standalone-preset.js, ConfigObject, OAuthConfigObject, oauth2-redirect.html, requestInterceptor, ResponseInterceptorFunction, SwaggerUIBundle, initOAuth, authPopup, authorizeOauth2WithPersistOption

Contributors

David Neuy

About

Swagger-UI example using ASP.NET Core (.NET 6) minimal web API project with implicit OAuth flow JSON Web Token authentication

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published