How to Use Json Web Tokens for Authentication and Authorisation

This article will focus on how json web tokens (JWTs) are used in authentication and authorisation flows. We will cover what JWTs are and then how they are used.

What is a JWT?

A JWT is a container for data that consists of three parts.

JWT header

The header contains token type and hashing algorithm (e.g. { "alg": "HS256", "typ": "JWT" }).

JWT payload

The payload contains claims about the user (e.g. { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }).

JWT claims are information about the token's subject or other relevant data. They are stored as key-value pairs within the token payload. These claims can include standard like those listed below, as well as custom fields specific to your application. Claims provide a way to securely transmit information between parties in a compact, self-contained manner, allowing systems to verify the token's authenticity and make authorization decisions based on its contents. Some examples of custom claims include role for role based access control, name for storing user information and login_source for tracking user details.

This is a list of commonly seen standard claims:

  • iss (issuer): The authentication server or identity provider that created the JWT. Validate this to ensure it comes from a trusted issuer.
  • sub (subject): Usually a unique identifier for the user or the entity the token represents.
  • aud (audience): Specifies which applications should accept this token. Validate this to ensure that token from one service isn't able to be reused for another service.
  • exp (expiration time): This is a Unix timestamp of when the token becomes invalid. Short lived tokens are common for security. Validate this to ensure the token is active. Allow a small leeway to account for clock time differences between servers.
  • nbf (not before): This is a Unix timestamp of when the token is valid. It is usually set to when the token was issued. Validate this for when tokens are issued in advance and may not be valid on issuance.
  • iat (issued at): This is a Unix timestamp of when the token was created. This can be used to implement token age restrictions that allow you to set an earlier expiry on a token dynamically.
  • scope (scopes): Granted scopes. Each endpoint in an api can be associated with some scopes and these scopes must be granted to the client for the client to call the action.

JWT signature

The signature is created by encoding the header and payload and then signing with a secret key and is used to ensure the token hasn't been tampered with.

Why are JWTs used for authentication and authorisation?

There are two main reasons why JWTs are used in authentication and authorisation: they are stateless and they are tamper-proof.

JWTs are stateless

The fact that JWTs contain claims about the user that tell the server who the user is and what resources they have access to and that the client sends this token in its HTTP requests allows the server to verify the user's identity without having to query the database. This stateless nature makes JWTs highly scalable and suitable for distributed systems and microservices architectures.

JWTs are tamper-proof

JWTs protect against tampering by using its signature during verification to ensure it has not been modified since the JWT's creation:

  • Signature creation: The server concatenates the Base64Url-encoded header and payload with a dot (.). The string is then hashed using the algorithm specified in the header and a secret key (this secret key is securly stored by the server). The resulting hash is the signature.
  • JWT Verification: When a JWT is received by the server, it is split into three parts: header, payload and signature. The server decodes the Base64Url-encoded header, payload and signature. The algorithm specified in the header is applied to the decoded header and payload and secret. If the output matches the Base64Url-decoded signature, then the JWT has not been modified since its creation.

Now that we've covered what JWTs are and why they are used, we can take a look at how they are used.

JWT Authentication and Authorisation Flow

0. Define Scopes

Before implementation of the flow, define a list of scopes that represent different permissions in the application (e.g. read:profile, write:posts, admin:users).

1. User Login

  1. User navigates to the login page.
  2. User enters their credentials (username and password).
  3. The client application specifies which scopes it is requesting for the session and then sends the credentials to the backend, usually via a POST request.

2. Server Authentication

  1. Server receives the login request and verifies the credentials using data from the database.
  2. If the credentials are invalid, the server returns an error response.

3. JWT Creation

  1. If the credentials are valid, the server creates a JWT.
  2. The server will also optionally create a refresh token and store it in the database.

4. Token Response

  1. Server responds to the client with the JWT. For this to be secure, ensure HTTPS is used to encrypt communication between server and client. If refresh tokens are used, they are sent to the client.
  2. This is usually done in the response body or as a HTTP-only cookie.

5. Client-Side Storage

  1. Client receives the JWT.
  2. Client stores the JWT, usually in local storage, session storage or as a cookie.

6. Subsequent Requests

  1. For each subsequent request to a protected route or resource, the client includes the JWT in the Authorization header or if it is stored as a HTTP-only cookie, it is automatically included.

7. Server Verification

  1. Server receives the request with the JWT.
  2. Server extracts the JWT from the Authorization header or cookie.
  3. Server verifies the JWT's signature using the secret key.
  4. Server checks the token's claims to see if the user has access or not.

8. Resource access

  1. If the user is both authenticated (has a valid JWT) and authorised (has the required permissions), the server processes the request and returns the protected resource.
  2. If the user is authenticated but not authorised, the server returns a 403 forbidden error. If the JWT is invalid or expired, the server returns a 401 unauthorised error

9. Token Refresh (Optional)

  1. JWTs are short lived for security reasons. (If someone got access to the JWT, they could perform the same actions as the user.)
  2. When the token is close to expiration, the client can request a new token using a refresh token by sending the refresh token to a specific endpoint.
  3. A new JWT is issued to the client if the refresh token is valid. User roles and permissions are applied to the JWT if they have changed since the last issuance.

10. Logout

  1. To logout, the client typically removes the JWT from its storage and the server can invalidate the token. If a token is invalidated then it cannot be used even if it hasn't expired yet.

11. Token Expiration

  1. If the user doesn't logout manually, the JWT will eventually expire.
  2. Once expired, the server will reject requests using that token.
  3. The user will need to login again to get a new valid token.

useful Links