JSON Web Token (JWT) Explained
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.
How JWT Works: Step-by-Step
1. User Authentication
User Login:
The user sends a login request to the server with their credentials (e.g., username and password).
POST /api/login Content-Type: application/json { "username": "user", "password": "password" }
Server Verification:
The server verifies the user's credentials. If they are valid, the server generates a JWT.
2. Token Generation
JWT Creation:
The server creates a JWT. A JWT typically consists of three parts: Header, Payload, and Signature.
Header:
{ "alg": "HS256", "typ": "JWT" }
Payload:
{ "sub": "userId", "name": "John Doe", "iat": 1516239022, "exp": 1516249022 }
sub
: Subject (the user ID)name
: User's nameiat
: Issued at (timestamp)exp
: Expiration time (timestamp)
Signature:
The signature is created by encoding the header and payload using Base64Url encoding, concatenating them with a dot, and then signing the result using a secret key and the algorithm specified in the header (e.g., HMAC SHA256).
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
JWT Response:
The server sends the generated JWT back to the client.
HTTP/1.1 200 OK Content-Type: application/json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0OTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }
3. Token Usage
Client Request with JWT:
The client includes the JWT in the Authorization header of subsequent requests to access protected resources.
GET /api/protected Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTUxNjI0OTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
4. Token Verification
Server Verification:
The server receives the request and extracts the JWT from the Authorization header.
The server verifies the JWT by checking the signature and the claims (e.g., expiration time).
Signature Verification:
The server re-creates the signature using the header and payload from the token and the secret key. If the signature matches the one in the token, it confirms that the token is valid and has not been tampered with.
Claims Verification:
The server checks the claims, such as expiration time (
exp
), to ensure the token is still valid.
5. Access Granted or Denied
Access Decision:
If the token is valid and the claims are verified, the server grants access to the protected resource.
If the token is invalid or expired, the server denies access and returns an appropriate error message.
HTTP/1.1 401 Unauthorized Content-Type: application/json { "error": "Unauthorized", "message": "Invalid or expired token" }
Summary
User Login: User sends credentials to the server.
Token Generation: Server verifies credentials and generates a JWT.
Token Usage: Client includes the JWT in the Authorization header of requests.
Token Verification: Server verifies the token's signature and claims.
Access Decision: Server grants or denies access based on the token's validity.
JWT Signature: Symmetric vs. Asymmetric
Symmetric Signature
In symmetric signing, the same secret key is used to sign and verify the JWT. This is typically done using algorithms like HMAC (e.g., HS256).
Signing:
The server creates the signature using the header, payload, and a secret key.
Example algorithm: HMACSHA256
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
Verification:
The server verifies the JWT by re-creating the signature using the same secret key and comparing it to the signature in the token.
Asymmetric Signature
In asymmetric signing, a pair of keys (public and private) is used. The private key signs the JWT, and the public key verifies it. This is typically done using algorithms like RSA or ECDSA (e.g., RS256, ES256).
Signing:
The server creates the signature using the header, payload, and a private key.
Example algorithm: RS256
RS256( base64UrlEncode(header) + "." + base64UrlEncode(payload), privateKey )
Verification:
The server (or any party with the public key) verifies the JWT by re-creating the signature using the public key and comparing it to the signature in the token.
How Private and Public Keys Work
Private Key
The private key is used to create the signature.
It must be kept secret and only accessible by the issuer (server) that creates the JWT.
When the server signs the JWT, it uses the private key to generate a unique signature based on the JWT's header and payload.
Public Key
The public key is used to verify the signature.
It can be freely distributed to any party that needs to verify the JWT.
When a server or client receives a JWT, it uses the public key to re-create the signature and compare it to the signature in the JWT.
If the signatures match, the JWT is considered valid and trusted.
Why Public Keys Are Sent
Verification: The public key is used by the recipient of the JWT to verify that the JWT was indeed signed by the server and has not been tampered with.
Trust: By distributing the public key, the server allows any recipient to verify the integrity and authenticity of the JWT, ensuring that the token can be trusted.
Differences and Use Cases
Symmetric:
Pros: Simpler and faster.
Cons: The same key must be shared between the parties, which can be a security risk.
Use Case: Internal applications where the key distribution is not an issue.
Asymmetric:
Pros: More secure as the private key never leaves the issuer, and the public key can be freely distributed.
Cons: Slower and more complex.
Use Case: Public APIs and scenarios where secure key distribution is required.
Example of Symmetric Signature (HS256)
Header:
{
"alg": "HS256",
"typ": "JWT"
}
Payload:
{
"sub": "userId",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516249022
}
Signature:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
Example of Asymmetric Signature (RS256)
Header:
{
"alg": "RS256",
"typ": "JWT"
}
Payload:
{
"sub": "userId",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516249022
}
Signature:
RS256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
privateKey
)
Comments
Post a Comment