Last updated: April 27, 2025
Table of Contents
1. Introduction: What is a JWT?
JSON Web Token, commonly known as JWT (pronounced "jot"), is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information, called "claims," can be verified and trusted because it is digitally signed.
Think of a JWT like a digitally signed passport: it contains verifiable information about the holder (claims), and the signature confirms its authenticity and that it hasn't been tampered with. Because JWTs are compact (small size) and self-contained (include all necessary info within them), they are widely used in web applications and APIs, especially for authentication and authorization scenarios.
2. JWT Structure: The Three Parts
A JWT consists of three distinct parts, separated by dots (.
):
Header.Payload.Signature
Each part (Header and Payload) is a JSON object that is Base64Url encoded. The Signature is created based on the encoded Header, encoded Payload, a secret or private key, and the algorithm specified in the header.
An example JWT might look like this (line breaks added for readability):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Let's break down each part.
3. The Header: Token Metadata
The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 (HS256) or RSA (RS256).
Example Header JSON:
{
"alg": "HS256",
"typ": "JWT"
}
alg
: Specifies the cryptographic algorithm used to sign the token. Common values includeHS256
(HMAC using SHA-256, symmetric),RS256
(RSA signature using SHA-256, asymmetric), andES256
(ECDSA signature using SHA-256, asymmetric).typ
: Declares the media type as "JWT".kid
(Key ID - Optional): Sometimes included, especially with asymmetric keys, to indicate which key was used to sign the token, helping the recipient select the correct public key for verification.
This JSON object is then Base64Url encoded to form the first part of the JWT. For the example above, this becomes eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
4. The Payload: Claims Information
The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically the user) and additional data.
There are three types of claims:
- Registered Claims: A set of predefined claims recommended by the JWT specification (RFC 7519). These are not mandatory but provide a standard set of useful, interoperable claims.
- Public Claims: Custom claims defined by those using JWTs, but registered in the IANA JSON Web Token Registry or defined as URIs with collision-resistant namespaces to prevent conflicts.
- Private Claims: Custom claims created for specific use cases between parties that agree on their meaning. These should be used with caution to avoid naming collisions.
Common Registered Claims include:
iss
(Issuer): Identifies the principal that issued the JWT.sub
(Subject): Identifies the principal that is the subject of the JWT (often the user ID).aud
(Audience): Identifies the recipients that the JWT is intended for (often the API or service that should accept the token).exp
(Expiration Time): Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing (Unix timestamp).nbf
(Not Before): Identifies the time before which the JWT MUST NOT be accepted for processing (Unix timestamp).iat
(Issued At): Identifies the time at which the JWT was issued (Unix timestamp).jti
(JWT ID): Provides a unique identifier for the JWT, which can help prevent replay attacks.
Example Payload JSON:
{
"sub": "user-12345",
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"exp": 1678886400,
"iat": 1678882800,
"jti": "unique-token-id-abc",
"roles": ["user", "reader"],
"name": "Alice Wonderland"
}
This JSON payload is then Base64Url encoded to form the second part of the JWT. For the example above, this becomes (approximately, actual encoding depends on whitespace): eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmV4YW1wbGUuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20iLCJleHAiOjE2Nzg4ODY0MDAsImlhdCI6MTY3ODg4MjgwMCwianRpIjoidW5pcXVlLXRva2VuLWlkLWFiYyIsInJvbGVzIjpbInVzZXIiLCJyZWFkZXIiXSwibmFtZSI6IkFsaWNlIFdvbmRlcmxhbmQifQ
.
Important Note: The payload is Base64Url encoded, *not* encrypted by default. Anyone can decode it. Therefore, never put sensitive information (like passwords) directly into the JWT payload unless the entire JWT is encrypted (using JWE - JSON Web Encryption), which is a separate standard.
5. The Signature: Ensuring Integrity
The third part is the signature. It's used to verify that the sender of the JWT is who it says it is and that the message wasn't changed along the way.
The signature is created by taking:
- The encoded Header
- A dot (
.
) - The encoded Payload
- A secret (for symmetric algorithms like HS256) or a private key (for asymmetric algorithms like RS256/ES256)
- Applying the signing algorithm specified in the header (
alg
).
Example using pseudocode for HS256:
Signature = HMACSHA256(
base64UrlEncode(Header) + "." + base64UrlEncode(Payload),
YOUR_SECRET_KEY
)
Common Signing Algorithms:
- HS256 (HMAC with SHA-256): A symmetric algorithm. Uses a single shared secret key for both signing and verification. Faster but requires secure sharing and storage of the secret.
- RS256 (RSA Signature with SHA-256): An asymmetric algorithm. Uses a private key to sign and a corresponding public key to verify. More secure for distributed systems as the private key never needs to be shared, but computationally more expensive than HS256.
- ES256 (ECDSA with SHA-256): An asymmetric algorithm using Elliptic Curve Cryptography. Offers similar security to RSA but with smaller key sizes and generally better performance than RS256.
The resulting signature is then Base64Url encoded to form the final part of the JWT.
6. How JWTs are Used
JWTs are commonly used in several scenarios:
- Authentication & Session Management: After a user logs in, the server creates a JWT containing user identity claims and sends it to the client. The client stores this token (e.g., in an HttpOnly cookie or memory) and includes it in subsequent requests to prove authentication. This enables stateless authentication, as the server doesn't need to store session state.
- Authorization: JWTs can contain claims representing user roles or permissions (scopes). When the client sends the JWT to access a protected API endpoint, the server verifies the signature and checks these claims to determine if the user is authorized to perform the requested action.
- Information Exchange: JWTs provide a secure way to transmit information between parties because their signature ensures integrity and authenticity.
- OpenID Connect (OIDC): The ID Token used in OIDC to convey user identity information is typically a JWT.
JWTs are usually sent in the Authorization
HTTP header using the Bearer
scheme:
Authorization: Bearer <token>
6.1 Example Authentication Flow
- Login Request (Client -> Server):
POST /login HTTP/1.1 Host: api.example.com Content-Type: application/json { "username": "alice", "password": "password123" }
- Server Verifies & Issues JWT:
- Server validates credentials ("alice", "password123").
- Creates Header:
{"alg": "HS256", "typ": "JWT"}
(Base64Url:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
) - Creates Payload:
{"sub": "alice123", "name": "Alice", "roles": ["user"], "iss": "myApp", "exp": 1678886400, "iat": 1678882800}
(Base64Url:eyJzdWIiOiJhbGljZTEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGVzIjpbInVzZXIiXSwiaXNzIjoibXlBcHAiLCJleHAiOjE2Nzg4ODY0MDAsImlhdCI6MTY3ODg4MjgwMH0
) - Generates Signature using a secret key:
HMACSHA256(encodedHeader + "." + encodedPayload, 'your-256-bit-secret')
-> (e.g., Base64Url:AbcDeFgHiJkLmNoPQrStUvWxYz12345EXAMPLE
) - Server Sends JWT in Response:
{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGljZTEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGVzIjpbInVzZXIiXSwiaXNzIjoibXlBcHAiLCJleHAiOjE2Nzg4ODY0MDAsImlhdCI6MTY3ODg4MjgwMH0.AbcDeFgHiJkLmNoPQrStUvWxYz12345EXAMPLE" }
- Client Stores JWT: The client application receives the
accessToken
and stores it securely (e.g., in memory or an HttpOnly cookie). - Client Accesses Protected Resource: Client makes a request to a protected endpoint, including the JWT.
GET /profile HTTP/1.1 Host: api.example.com Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhbGljZTEyMyIsIm5hbWUiOiJBbGljZSIsInJvbGVzIjpbInVzZXIiXSwiaXNzIjoibXlBcHAiLCJleHAiOjE2Nzg4ODY0MDAsImlhdCI6MTY3ODg4MjgwMH0.AbcDeFgHiJkLmNoPQrStUvWxYz12345EXAMPLE
- Server Verifies JWT & Responds:
- Server receives the request and extracts the token from the
Authorization
header. - Decodes the Header and Payload (without verifying yet).
- Checks the
alg
in the header (HS256). - Re-calculates the signature using the received encoded header, encoded payload, and its *own* copy of the secret key:
HMACSHA256(encodedHeader + "." + encodedPayload, 'your-256-bit-secret')
- Compares the recalculated signature with the signature received in the token. If they match, the token is authentic and unmodified.
- Validates claims: Checks if
exp
is in the future,iss
is trusted,aud
matches (if present), etc. - If all checks pass, the server trusts the claims (e.g., knows the request is from user "alice123" with role "user") and processes the request, returning the profile data.
- If any check fails (signature mismatch, expired token, etc.), the server returns a
401 Unauthorized
error.
- Server receives the request and extracts the token from the
7. Security Considerations
While JWTs provide significant benefits, they must be implemented correctly to be secure:
- Use HTTPS: Always transmit JWTs over HTTPS to prevent interception.
- Validate Signatures Always: The most critical step. The receiving party MUST validate the signature using the correct secret or public key before trusting any claims. Failure to do so makes the token meaningless.
- Validate Claims: Always validate registered claims like
exp
(check if expired),nbf
(check if active yet),aud
(check if intended for this recipient), andiss
(check if from a trusted issuer). - Algorithm Security:
- Verify the
alg
header claim matches the expected algorithm. - Crucially, reject tokens with
alg: none
unless explicitly required and understood. Acceptingnone
bypasses signature validation entirely. - Choose strong algorithms (e.g., RS256/ES256 over HS256 if the secret cannot be perfectly secured or needs sharing).
- Verify the
- Sensitive Data: Remember the payload is only encoded, not encrypted. Do not store sensitive data (passwords, PII) in the payload unless using JWE (JSON Web Encryption).
- Prevent Replay Attacks: Use the
jti
(JWT ID) claim combined with server-side tracking to ensure a token cannot be reused, or keep token lifetimes very short. - Token Storage (Client-Side): Storing JWTs securely in the browser is challenging.
localStorage
/sessionStorage
: Convenient but vulnerable to Cross-Site Scripting (XSS) attacks, allowing attackers to steal the token. Generally discouraged for sensitive tokens.HttpOnly
Cookies: More secure against XSS as they aren't accessible via JavaScript. However, they can be vulnerable to Cross-Site Request Forgery (CSRF) if not protected (e.g., usingSameSite
attribute).- In-Memory Storage: Storing the token only in JavaScript variables is most secure against XSS/CSRF but doesn't persist across page reloads/tabs.
- Token Revocation: JWTs are inherently stateless, making immediate revocation difficult. Strategies include maintaining server-side blocklists (using the
jti
claim) or keeping token lifetimes very short and relying on refresh token revocation.
8. Conclusion
JSON Web Tokens provide a standardized, compact, and self-contained method for securely transmitting information as claims between parties. Understanding their structure (Header, Payload, Signature) and the different types of claims is essential for using them effectively. While powerful for authentication, authorization, and information exchange, JWT security relies heavily on correct implementation. Developers must prioritize HTTPS, rigorously validate signatures and claims, choose appropriate algorithms, protect against common vulnerabilities like replay attacks, and carefully consider secure token storage strategies.
9. Additional Resources
Related Articles
- OAuth 2.0 Explained for Developers
- OpenID Connect (OIDC) Fundamentals for Developers
- SPA Authentication: JWT vs Cookies
- Understanding the OWASP Top 10 for Web Security
- API Design Best Practices: Versioning and Idempotency