Intro

This is the third and last blog about JWT (JSON Web Token). In the first blog I explained how you can create a JWT, in the second we secured the REST service. In this last blog we secure the web application with JWT and covers these topics:

  • Setup and configure JWT
  • Setup Authentication Cookies
  • Connect to JWT Issuer
  • JWT Storage
  • Authentication Cookies
  • ClaimPrincipalManager
  • Sliding Expiration
  • Policies in razor views
  • Accessing REST service

General JWT Security Overview

Before we dive into the details first a refresher on part one and two. The JWT issuer and the REST service are up and running.

Setup and configure JWT

The JWT setup and configuration for the website and the REST service is the same. It starts with adding the Microsoft.AspNetCore.Authentication.JwtBearer package. The JWT package needs configuring in startup.cs First we set the parameters in ‘appsettings.json’

The SecretKey value must match the key in the JWT issuer server otherwise the user will remain unauthenticated and access will be denied. DI (Dependency Injection) delivers access to the configuration:

JwtTokenValidationSettingsFactory implements the interface and has the function TokenValidationParameters.

The function TokenValidationParameters returns (as the name suggest) JWT validation parameters. These parameters are used during startup

JWT is now ready to use.

Get JWT from Issuer

We need connect to the JWT issuer in order to get the token. The connection parameters are set in appsettings.json

Login delivers  JWT based om user credentials and RenewToken refreshes the expiration window for a valid ticket. I explain this later in more detail. The application reads the configuration with help from DI (Dependency Injection).

The ClaimPrincipalManager uses the setting during a JWT request.

JWT Storage

Web applications are stateless by design. The web application needs some kind of storage for the JWT, otherwise the token must be retrieved every time again for a page request. The application can store the JWT at:

  • HTML5 Web Storage also known as local storage
  • Cookie

Stormpath has a great blog where pros and cons are explained in detail. Web storage has one big disadvantage, the storage is also accessible to others and the web application will have no notion. This makes Cookie storage the preferred option.

Authentication Cookies

It may seems odd but Authentication Cookies handles the security and not JWT.  Authentication Cookies handles the authentication, authorization and stores the JWT.  Authentication Cookies is hosted in package ‘Microsoft.AspNetCore.Authentication.Cookies‘.  Please view the video tutorial if you want more information about the authentication with cookies.

The login process boils down to:

  1. Collect credentials (email and password).
  2. Get JWT from issuer.
  3. Create user and claims from JWT.
  4. Add JWT to user claims.
  5. Sign in with user and cookie settings .

Step 4, adding the original token to the user claims is not needed for authentication or authorization purposes but gives the opportunity to extract the JWT from the user. The extracted JWT is used for accessing the REST service and sliding expiration.  The login is handled by the ClaimPrincipalManager:

ClaimPrincipalManager

The ClaimPrincipalManager provides easy access to all the security related stuff and implements the IClaimPrincipalManager interface. The interface is registered during startup and an instance is available by the DI (Dependency Injection) pattern. The ClaimPricipalManager is not part of any package, it’s only available in the web application.

Sliding Expiration

The JWT expiration is fixed and has no sliding features. When the JWT becomes expired, REST service calls will fail. The Cookie Authentication provides hooks where we can inject the custom code. The algorithm is simple:

  • Check on every page request if the JWT is about to expire.
  • Fetch renewed JWT from the Issuer
  • Login with the renewed JWT

The implementation refreshes when the expiration is half way or more. Login with the renewed JWT makes the cookie authentication expiration also sliding and makes sure the user has up to date claims.

The refresh hook is set during startup:

The fresh hook only checks if refresh is required:

The necessary datetime’s are fetch from user claims and where set during login. The ClaimPrincipalManager handles the actual token renewal:

The token renewal works only when not yet expired JWT. If the token is already expired the renewal will fail.

Policies in razor views

In real world application the user interface depends on the user permissions. In our web application shows employees. Only the HR (Human Resource) manager is allowed to delete employees. In my previous post I explained a policy requires one or more claims. The policy are registered during startup.

The ClaimPrincipleManager implements the HasPolicy function

The function relies on interface IAuthorizationService. This interface is available in package ‘Microsoft.AspNetCore.Authorization’ and is available for DI without explicit registration during startup.

The @inject syntax in a razor view gives returns a IClaimPrincipalManager instance and can be used for policies in a razor  view:

Accessing REST service

The web application receives the employees resources from the REST service.  The pattern to get it work becomes familiar:

  • Specify settings in appsettings.json
  • Settings class matches the fieldnames in appsettings.json
  • Create Interface for REST client
  • Create Interface Factory
  • Register settings, interface and factory during startup.
  • Inject Interface in Controller

REST Client settings

Settings mapping Interface and interface factory

Registration during startup

Inject REST client in EmployeeController

And use client in the controller

How the client works

The User is passed a parameter in CreateClient(…). The user has the JWT as private claim available and is added to DefaultRequestHeaders and the REST client can now be authorized on the REST server.

Application demo

Thank you for getting this far. It was a lot to cover and now its demonstration time

Start screen:

Click on ‘Employees’ redirects to login page. Login with (password = password)

  • employee@xyz.com
  • hrwoker@xyz.com
  • hrmanager@xyz.com

Login with employee@xyz.com

Login with hrmanager@xyz.com

As you can see the user interface depends on the user.

Visual Studio Startup Projects

Sometimes the Visual Studio startup Project is lost and prevent running the application. Right click on the solution and choose ‘Set Startup Projects…’

And repair the startup setting:

Choose either WebApp or Jwt.ConsoleDemo deppending on what you want.

Conclusion

JWT combined with  authorization cookies secures web applications and REST services and still offers SSO (Single Sign On) for the user. JWT is self contained, scalable and it platform independent.

Further Reading

Previous post: JWT Security Part 2, Secure REST service

Where to Store your JWTs – Cookies vs HTML5 Web Storage

ASP.NET Core Authorization Video

ASP.NET Core Authorization Video demonstrated Source Code

Comments are closed.