JSON Web Tokens Explained
Learn what a JSON Web Token (JWT) is including JSON Web Tokens vs sessions (traditional sessions), JWT structure, and JWT security.
Table of Contents 📖
- What is a JSON Web Token?
- JSON Web Token Structure
- JSON Web Token Header
- JSON Web Token Payload
- JSON Web Token Signature
- What to Store in a JSON Web Token
- How JSON Web Tokens Work
- JSON Web Tokens vs Traditional Sessions
What is a JSON Web Token?
A JSON Web Token, or JWT, is an RFC specification that defines a way to securely transmit information between entities. This information is transmitted as a JSON object, hence the name JSON Web Token. Common use cases for JWTs are authorization and general information exchange. JWTs are excellent for these use cases as they have small overhead and ensure integrity through signing of the token.
JSON Web Token Structure
JWTs consist of a header, payload, and signature. These three parts are separated by dots (header.payload.signature).
eyJhbGciIkpXVCJ9.eyJzdWIibmFtZyfQ.SflKxwRQssw5c
The header and payload are each Base64Url encoded, decoding them would reveal a JSON object. The JWT signature is a hash used to verify the integrity of the token.
JSON Web Token Header
The header of a JWT contains information on the type of token and the signing algorithm used. For example, the below header specifies the type of the token to be a JWT and the algorithm to be HMACSHA256.
{ "alg": "HS256", "typ": "JWT" }
This header would then be base64Url encoded to create something like the following.
eyJhbGciIkpXVCJ9
JSON Web Token Payload
The payload of a JWT contains claims and additional data. Claims are essentially just key value pairs that provide information. There are 3 different types of claims: public, private, and registered. Registered claims are claims whose use is very strictly defined. An example of a registered claim is iss which is short for issuer, it holds the information about who issued the JWT.
// Header { "alg": "HS256", "typ": "JWT" }, // Payload { "iss": "WittCode" }
Public claims are defined in the public registry of JWT claims. These claims are well documented and publicly available. An example of a public claim is auth_time which is the time in seconds since January 1st 1970 when the authentication occurred.
// Header { "alg": "HS256", "typ": "JWT" }, // Payload { "iss": "WittCode", "auth_time": "1677110405" }
Private claims are claims only known to the consumer and producer of the JWT. For example, a private claim could be a field like fav_witt.
// Header { "alg": "HS256", "typ": "JWT" }, // Payload { "iss": "WittCode", "auth_time": "1677110405", "fav_witt": "everything" }
JSON Web Token Signature
The JWT signature is a hash of the encoded header and encoded payload joined by a dot with a secret. The hashing algorithm used is the one specified in the JWT header and the secret ensures that third parties cannot verify the signature as they don't have the secret.
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
The purpose of the cryptographic JWT signature is to verify the integrity of the token. In other words, as it consists of the payload and header, if the payload and/or header are altered then the signature will change. Indicating that the token has been altered.
What to Store in a JSON Web Token
Sensitive information should not be stored inside a JWT as JWTs are not encrypted, they are encoded. Therefore, the base64Url encoding can easily be decoded. The signature is used to ensure integrity, it does not encrypt the data in the JWT. As such, it is strongly recommended to use HTTPS with JWTs.
How JSON Web Tokens Work
Lets demonstrate how JWTs work by using a classic login form. First, a user logs in using a username and password, the server that authenticated the user returns a JWT. There is no standardized way on how the server should return the JWT token. For example, it could be returned in the body of the response or even in a HTTP header. The token is then stored on the client. Next, with each subsequent request, the JWT is provided to the Authorization HTTP Header with the Bearer schema. The server then extracts the token from the Authorization header and checks the JWT signature. If the token is valid, then the client is given access to the resource.
JSON Web Tokens vs Traditional Sessions
The traditional alternative to JWTs is sessions stored on the server. These sessions are identified with a session id. Specifically, when a user signs in with their username and password, the server creates a session and returns a session id to the user to identify the session. Next, with each subsequent request, the session id is sent too, allowing the server to look up the session information for that user from a database. This is a perfectly fine solution but it can introduce synchronization and speed issues when scaling the application (adding more servers and databases).
On the other hand, JWTs maintain session state on the client. Therefore, they do not require any information to be looked up by the server, they just need to be validated by the server. As a result, scaling is not an issue and nor is speed as there is usually no need for a database lookup with each request.