Skip to main content

JWT

JSON Web Token

RFC 7519 - https://datatracker.ietf.org/doc/html/rfc7519

https://en.wikipedia.org/wiki/JSON_Web_Token

This is a stateless authentication mechanism as the user state is never saved in server memory. The server's protected routes will check for a valid JWT in the Authorization header, and if it is present, the user will be allowed to access protected resources. As JWTs are self-contained, all the necessary information is there, reducing the need to query the database multiple times.

https://jwt.io

https://token.dev

JWT = JSON Data + Signature source

JWT are self-contained.

What is token-based authentication? https://stackoverflow.com/questions/1592534/what-is-token-based-authentication This answer lists some advantages (eg CSRF safe): https://stackoverflow.com/a/27119226/4034572

Anatomy of a JWT: https://news.ycombinator.com/item?id=30499618 - https://fusionauth.io/learn/expert-advice/tokens/anatomy-of-jwt

Security cheatsheet: https://assets.pentesterlab.com/jwt_security_cheatsheet/jwt_security_cheatsheet.pdf

https://github.com/shieldfy/API-Security-Checklist#jwt-json-web-token

  • Use a random complicated key (JWT Secret) to make brute forcing the token very hard.
  • Don't extract the algorithm from the header. Force the algorithm in the backend (HS256 or RS256).
  • Make token expiration (TTL, RTTL) as short as possible.
  • Don't store sensitive data in the JWT payload, it can be decoded easily.
  • Avoid storing too much data. JWT is usually shared in headers and they have a size limit.

https://www.manning.com/liveproject/fixing-vulnerabilities - Part of https://www.manning.com/liveprojectseries/json-web-token-ser

Signing

Since anyone can produce a JWT token, the signature is used to verify the authenticity. This way only the server can issue new tokens using the secret.

signature = hash_algorithm(secret, base64urlEncoding(header) + '.' + base64urlEncoding(payload))

JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA. source

Encryption

https://en.wikipedia.org/wiki/JSON_Web_Encryption

RFC 7516 - https://datatracker.ietf.org/doc/html/rfc7516

JWT are signed and can optionally be encrypted too.

Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. source

Unless encrypted, the contained information is public, anyone can read/decode it. Hence, do not store sensitive information into it.

If you can decode JWT, how are they secure? - https://stackoverflow.com/questions/27301557/if-you-can-decode-jwt-how-are-they-secure

https://github.com/nextauthjs/next-auth#secure-by-default

When JSON Web Tokens are enabled, they are encrypted by default (JWE) with A256GCM

Stateless

https://stackoverflow.com/questions/55881611/why-jwt-is-a-stateless-authentication

https://www.jbspeakr.cc/purpose-jwt-stateless-authentication

Format

header.payload.signature

Which algorithm is used to sign.

{
"alg": "HS256",
"typ": "JWT"
}

Payload

Contains the claims, which can be Registered (ie standard fields), Public (which should be registered in the IANA "JSON Web Token Claims" registry) or Private.

{
"iat": 1422779638,
"role": "admin"
}

Eg iat is Issued At Time.

Signature

signature = hash_algorithm(secret, base64urlEncoding(header) + '.' + base64urlEncoding(payload))

Token

token = base64urlEncoding(header) + '.' + base64urlEncoding(payload) + '.' + base64urlEncoding(signature)

alg=none

How Many Days Has It Been Since a JWT alg=none Vulnerability? https://www.howmanydayssinceajwtalgnonevuln.com/

From https://en.wikipedia.org/wiki/JSON_Web_Token#Vulnerabilities:

Security consultant Tim McLean reported vulnerabilities in some JWT libraries that used the alg field to incorrectly validate tokens, most commonly by accepting a alg=none token. While these vulnerabilities were patched, McLean suggested deprecating the alg field altogether to prevent similar implementation confusion.[10] Still, new alg=none vulnerabilities are still being found in the wild, with four CVEs filed in the 2018-2021 period having this cause.

With proper design, developers can address algorithm vulnerabilities by taking precautions:

  1. Never let the JWT header alone drive verification
  2. Know the algorithms (avoid depending on the alg field alone)
  3. Use an appropriate key size

How I Found An alg=none JWT Vulnerability in the NHS Contact Tracing App - https://www.zofrex.com/blog/2020/10/20/alg-none-jwt-nhs-contact-tracing-app/

Store JWT on the client

Also see Authentication#SPA.

If we store it on localStorage we are open to XSS. (Using sessionStorage doesn't make sense since it's cleared when the tab is closed.)

Where to store JWT in browser? How to protect against CSRF? - https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf

Should JWT be stored in localStorage or cookie? - https://stackoverflow.com/questions/34817617/should-jwt-be-stored-in-localstorage-or-cookie

Do not use it for user sessions

JSON Web Tokens (JWT) are Dangerous for User Sessions—Here’s a Solution - https://redis.com/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/

The biggest problem with JWT is the token revoke problem

Could have stale data

Imagine the user is an admin and got demoted to a regular user with fewer permissions. Again this won’t take effect immediately and the user will continue to be an admin until the token expires.

The state needs to be maintained anyway (for rate-limiting, IP-whitelisting, etc.)

In many real-world apps, servers have to maintain the user’s IP and track APIs for rate-limiting and IP-whitelisting. So you’ll need to use a blazing fast database anyway. To think somehow your app becomes stateless with JWT is just not realistic.

Where can I use it?

There are scenarios where you are doing server-to-server (or microservice-to-microservice) communication in the backend and one service could generate a JWT token to send it to a different service for authorization purposes And other narrow places, such as reset password, where you can send a JWT token as a one-time short-lived token to verify the user’s email.

JWT should not be your default for sessions - https://news.ycombinator.com/item?id=27136539 - https://evertpot.com/jwt-is-a-bad-default/

it’s not needed to have a system for session data, like Redis or a database. All the information is contained in the JWT, it means your infrastructure is in theory simpler. You’re potentially making fewer calls to a data-store on a per-request basis.

cannot 'kill' a session without building complex (and stateful!) infrastructure to explicitly detect and reject them, defeating the entire point of using stateless JWT tokens to begin with.

Why JWTs Suck as Session Tokens - https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens

The way I like to think of JWTs is that they’re just some JSON data that you can verify came from someone you know.

When the server receives a JWT, it can validate that it is legitimate and trust that the user is whoever the token says they are. The server can validate this token locally without making any network requests, talking to a database, etc. This can potentially make session management faster because instead of needing to load the user from a database (or cache) on every request, you just need to run a small bit of local code. This is probably the single biggest reason people like using JWTs: they are stateless.

There are several cases in which JWTs can be useful. If you’re building API services that need to support server-to-server or client-to-server (like a mobile app or single page app (SPA)) communication, using JWTs as your API tokens is a very smart idea.

Ask HN: What's the current sentiment on JWT for stateless auth tokens? - https://news.ycombinator.com/item?id=21783303

Why you should not use JWT - https://news.ycombinator.com/item?id=33019960 - https://apibakery.com/blog/tech/no-jwt/

Major advantage of JWT compared to bearer tokens (or indeed, session authentication) is that they don't require looking up the token. If you have a distributed system, each node in the system can verify JWT correctness for itself and immediately use the data - no need to look up the random string in the database to figure out who it is.

That's great if you've got a true microservices architecture. Your auth service can check user credentials (email and password, or using a 3rd-party auth provider), issue a JWT and call it a day. Other microservices can independently verify the correctness of the token and have the user information immediately, without the need to check in with the auth service. This shaves precious time off of every request handling and lowers the load on your auth service. What's not to like?

Regarding the refresh token:

you've just reintroduced a bearer token, because that's exactly what the refresh token is. Looking at JWTs from that perspective, you've introduced a client-side cache of user identity (the JWT) and added a bunch of complexity (involving the creation, verification, and token refresh) for the hope of optimizing part of the work you used to do on the server (checking user identity using a bearer token). Was it worth it?

JWT vs. Opaque Tokens - https://news.ycombinator.com/item?id=33018135 - https://zitadel.com/blog/jwt-vs-opaque-tokens

users can get a token from your authorization server and use it in another without those servers needing to consult a central service.

a self-contained token that is issued is not easy to revoke, but there are a few ways to work around this. For example, you can add an exp claim which signifies an expiration date for the token. Or you can use the jti claim to assign a valid identifier. Using the identifiers, you can create blacklists to block certain token identifiers.

In contrast, opaque tokens are stored on the server. So you can change their contents at will. If a user is banned or deleted, or if any other action is taken that would invalidate their token, you can instantly revoke the token that is residing in your storage. There is no window to use an invalid token.

For this reason, JWT tokens are a bad choice for storing long-lasting authorization and session data. Because of the necessity to include an expiration date with your tokens, you can't really issue them for too long. And if you want to end a session, you can't really make the token invalid.

there are some situations where the self-sufficient nature of JWTs shine. For example, if your system is highly distributed, querying the authorization server for the token details of opaque tokens may create additional internal traffic to the server, increase overall latency, and create a bottleneck for the system.

Libraries

https://github.com/topics/jwt

https://jwt.io/libraries

JavaScript

https://github.com/auth0/node-jsonwebtoken/

https://github.com/auth0/express-jwt - connect/express middleware that validates a JsonWebToken (JWT) and set the req.user with the attributes

https://github.com/auth0/jwt-decode - Decode JWT tokens; useful for browser applications.

https://github.com/panva/jose - JWA, JWS, JWE, JWT, JWK, JWKS with no dependencies.

https://github.com/kjur/jsrsasign