JWT Security Guide: How JSON Web Tokens Work and How to Secure Them
Why JWT Security Matters
JSON Web Tokens have become the dominant standard for authentication and authorization in modern web applications. According to the 2025 OWASP API Security Report, over 78% of APIs now rely on JWT-based authentication mechanisms. From single-page applications to microservice architectures, JWTs carry identity claims, session data, and access permissions across network boundaries.
However, the widespread adoption of JWTs has also made them a prime target for attackers. Misconfigured token validation, weak signing keys, and overlooked algorithm vulnerabilities have led to thousands of breaches. In 2025 alone, researchers documented over 12,000 critical JWT-related vulnerabilities across public bug bounty programs.
Understanding how JWTs work at a fundamental level is not optional for developers—it is a security necessity. In this guide, we will break down the JWT structure, explain how signing algorithms function, walk through the most common attack vectors, and provide actionable best practices for securing tokens in production.
What is a JWT?
A JSON Web Token (JWT) is a compact, self-contained token defined by the RFC 7519 standard. It encodes a set of claims (statements about an entity, typically a user) as a JSON object. This JSON object is then serialized and signed or encrypted to produce a URL-safe string.
JWTs serve two primary purposes:
-
Authentication: After a user logs in, the server issues a JWT containing the user’s identity. The client includes this token in subsequent requests to prove who they are.
-
Authorization: The JWT carries claims about what the user is allowed to do (e.g., “role: admin”, “scope: read-write”). The server verifies the token and grants or denies access based on these claims.
Unlike session-based authentication, JWTs are stateless. The server does not need to store session data—it only needs to verify the token’s signature. This makes JWTs particularly well-suited for distributed systems, microservices, and serverless architectures.
The Three-Part JWT Structure
Every JWT consists of three Base64url-encoded segments separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Each segment serves a specific purpose:
1. Header (Segment 1)
The header typically contains two fields:
alg: The signing algorithm used (e.g.,HS256,RS256,ES256)typ: The token type, almost always"JWT"
Example decoded header:
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (Segment 2)
The payload contains the claims—statements about the entity being authenticated. Claims fall into three categories:
- Registered Claims: Standardized fields defined by the JWT specification (e.g.,
iss,sub,exp,nbf,iat,jti) - Public Claims: Custom claims defined by the application (e.g.,
"role": "admin","email": "user@example.com") - Private Claims: Claims agreed upon between the issuer and the consumer
Example decoded payload:
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"iat": 1719000000,
"exp": 1719003600
}
3. Signature (Segment 3)
The signature is the result of applying a cryptographic algorithm to the encoded header, encoded payload, and a secret key. This is where security lives—the signature ensures that the token has not been tampered with.
HMAC-SHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
JWT Structure Breakdown Table
| Segment | Content | Encoding | Purpose | Tamper-Proof? |
|---|---|---|---|---|
| Header | Algorithm and token type | Base64url | Identifies signing method | No (readable by anyone) |
| Payload | Claims and user data | Base64url | Carries identity and permissions | No (readable by anyone) |
| Signature | Cryptographic hash | Binary | Verifies integrity | Yes (requires secret key) |
Critical insight: The header and payload are only Base64url-encoded, not encrypted. Anyone can decode a JWT and read its contents. JWTs provide integrity (through signatures), not confidentiality (through encryption). If you need to hide the payload contents, use JWE (JSON Web Encryption) instead.
How JWT Signing Works
Signing is the mechanism that ensures a JWT has not been modified after issuance. There are three main categories of signing algorithms:
Symmetric Algorithms (HMAC)
In HMAC (Hash-based Message Authentication Code) signing, the same secret key is used to both create and verify the signature.
How it works:
- The server generates a strong secret key (e.g.,
HS256uses a 256-bit key). - When issuing a token, the server computes
HMAC-SHA256(header + payload, secret). - When verifying, the server recomputes the signature and compares it to the one in the token.
Pros:
- Fast (single key operation)
- Simple to implement
- Good for single-server architectures
Cons:
- The same key is used for signing and verification
- Not suitable for distributed systems where multiple services need to verify tokens independently
Common HMAC variants:
| Algorithm | Key Size | Hash Function | Security Level |
|---|---|---|---|
| HS256 | 256 bits | SHA-256 | Strong (recommended) |
| HS384 | 384 bits | SHA-384 | Very strong |
| HS512 | 512 bits | SHA-512 | Very strong |
Asymmetric Algorithms (RSA/ECDSA)
Asymmetric algorithms use a key pair: a private key for signing and a public key for verification.
How it works:
- The server keeps the private key secret.
- The public key is distributed to services that need to verify tokens.
- When issuing, the server signs with the private key.
- When verifying, any service with the public key can validate the signature independently.
Pros:
- Multiple services can verify tokens without sharing a secret
- More secure for distributed architectures
- Public keys can be safely shared
Cons:
- Slower than HMAC (asymmetric cryptography is more computationally expensive)
- Key management is more complex
Common asymmetric variants:
| Algorithm | Key Type | Curve/Size | Security Level |
|---|---|---|---|
| RS256 | RSA | 2048+ bits | Strong |
| RS384 | RSA | 3072+ bits | Very strong |
| RS512 | RSA | 4096+ bits | Very strong |
| ES256 | ECDSA | P-256 curve | Strong (smaller keys) |
| ES384 | ECDSA | P-384 curve | Very strong |
| ES512 | ECDSA | P-521 curve | Very strong |
| EdDSA | EdDSA | Ed25519 | Strong (fastest) |
When to Choose HMAC vs. RSA/ECDSA
| Scenario | Recommended Algorithm | Reason |
|---|---|---|
| Single server, monolithic app | HMAC (HS256) | Fast, simple, one secret |
| Microservices (3+ services) | RSA (RS256) or ECDSA (ES256) | Public key distribution |
| High-performance API gateway | HMAC (HS256) | Lowest latency |
| Third-party API authentication | RSA (RS256) | Industry standard |
| Mobile app backend | ES256 | Small key size, fast verification |
Common JWT Vulnerabilities
Understanding how JWTs break is just as important as understanding how they work. Here are the most dangerous attack vectors:
1. The “None” Algorithm Attack
The JWT specification includes a "none" algorithm, which indicates that the token is unsigned. While intended for unsigned tokens in controlled environments, this has become one of the most exploited JWT vulnerabilities.
How the attack works:
- Attacker takes a valid JWT.
- Changes the header
"alg"from"HS256"to"none". - Removes the signature.
- Sends the modified token to the server.
If the server does not explicitly reject "none" as an algorithm, it will accept the token as valid.
Impact: Complete authentication bypass. The attacker can forge any token with any claims.
Mitigation: Always specify the allowed algorithms explicitly. Never accept "none" unless you explicitly need unsigned tokens.
2. Algorithm Confusion (Key Confusion)
This attack exploits the difference between symmetric and asymmetric algorithms. In an RSA-signed system, the server uses a private key to sign and distributes the public key for verification.
How the attack works:
- Attacker obtains the server’s RSA public key.
- Creates a token signed with HMAC-SHA256 using the RSA public key as the HMAC secret.
- Changes the header
"alg"from"RS256"to"HS256". - The server, if configured to accept both algorithms, verifies the HMAC signature using the public key as the secret—which matches.
Impact: Complete authentication bypass. The attacker can forge arbitrary tokens.
Mitigation: Never accept multiple algorithm types. Pin the algorithm in your verification code. Do not derive the algorithm from the token header.
3. Weak Secret Keys
HMAC algorithms are only as strong as the secret key. A weak or predictable secret can be brute-forced offline.
Risk factors:
- Short keys (less than 256 bits for HS256)
- Predictable keys (e.g.,
"secret123","my-jwt-key") - Keys derived from passwords (low entropy)
- Default keys shipped with frameworks
Mitigation: Use cryptographically random keys of at least 256 bits for HS256. Generate secrets using our Password Generator or Secret Token Generator.
4. Token Theft and Replay Attacks
If an attacker obtains a valid JWT (through XSS, network interception, or social engineering), they can use it until it expires.
Mitigation strategies:
- Use short expiration times (5-15 minutes for access tokens)
- Implement refresh token rotation
- Bind tokens to specific clients (e.g., include a client fingerprint hash)
- Use token revocation lists for sensitive operations
5. Missing Expiration Claims
JWTs without an exp claim remain valid indefinitely. This is a common oversight in development that creates a persistent attack surface.
Mitigation: Always include both exp (expiration) and nbf (not before) claims. Set reasonable time limits based on the sensitivity of the operation.
6. Insecure Token Storage
Even a perfectly signed JWT is vulnerable if stored insecurely on the client side.
Risky storage locations:
localStorage(accessible to any JavaScript on the page)sessionStorage(same as localStorage, plus cleared on tab close)- Cookies without
HttpOnly,Secure, orSameSiteflags
Safer alternatives:
HttpOnlycookies (not accessible via JavaScript)- Short-lived tokens in memory with refresh tokens in HttpOnly cookies
- Use our Entropy Calculator to measure the strength of your token storage strategy
JWT Security Best Practices
Based on industry standards and real-world incident analysis, here are the essential practices for securing JWTs in production:
1. Always Validate the Signature
Never trust a JWT without verifying its signature. Use a well-maintained JWT library rather than implementing verification manually. Popular libraries include:
- JavaScript:
jsonwebtoken,jose - Python:
PyJWT,python-jose - Go:
golang-jwt/jwt - Java:
java-jwt(by Auth0)
2. Pin the Algorithm
Always specify the expected algorithm in your verification code. Do not read the alg field from the token header to determine the verification method.
# BAD: Algorithm derived from token
jwt.decode(token, key)
# GOOD: Algorithm pinned explicitly
jwt.decode(token, key, algorithms=["HS256"])
3. Use Short Expiration Times
| Token Type | Recommended Expiration | Use Case |
|---|---|---|
| Access Token | 5-15 minutes | API requests |
| ID Token | 1-24 hours | User identity |
| Refresh Token | 7-30 days | Token renewal |
| Service Token | 1-60 minutes | Inter-service auth |
4. Generate Strong Signing Keys
For HMAC algorithms, use a minimum of 256 bits of entropy. For RSA, use at least 2048-bit keys. For ECDSA, use the P-256 curve or stronger. You can generate cryptographically secure random keys using our Secret Token Generator.
5. Validate All Claims
Beyond the signature, verify these claims on every request:
exp: Token has not expirednbf: Token is not used before its valid timeiss: Token was issued by the expected authorityaud: Token is intended for your APIsub: Subject claim matches the authenticated user
6. Use HTTPS Everywhere
JWTs transmitted over HTTP are vulnerable to interception and modification. Always enforce HTTPS in production. Configure HSTS (HTTP Strict Transport Security) headers to prevent downgrade attacks.
7. Implement Token Revocation
While JWTs are stateless, there are cases where you need to revoke tokens before they expire:
- User logout
- Password change
- Suspicious activity detection
- Account deletion
Consider maintaining a short-lived denylist (stored in Redis or similar) for revoked token IDs (jti claims).
8. Avoid Sensitive Data in Payloads
Since JWT payloads are only Base64url-encoded (not encrypted), never include sensitive data like passwords, credit card numbers, or personal health information. If confidentiality is required, use JWE (JSON Web Encryption) or transmit sensitive data through encrypted channels.
JWT vs. Session Cookies: A Security Comparison
| Factor | JWT (Stateless) | Session Cookies (Stateful) |
|---|---|---|
| Server Storage | No session data stored | Session data stored in memory/DB |
| Scalability | Excellent (no shared state) | Requires shared session store |
| Revocation | Difficult (requires denylist) | Easy (delete session from store) |
| XSS Risk | High (if in localStorage) | Lower (HttpOnly cookies) |
| CSRF Risk | Low (not automatically sent) | Higher (cookies auto-sent) |
| Mobile Support | Excellent | Complex (cookies vary by platform) |
| Payload Size | Large (contains claims) | Small (session ID only) |
| Cross-Domain | Easy (no cookie restrictions) | Complex (SameSite policies) |
For most modern web applications, a hybrid approach works best: use short-lived JWTs for API authorization and HttpOnly cookies for session management. This gives you the scalability benefits of JWTs while mitigating the XSS risks associated with token storage.
Frequently Asked Questions
Are JWTs more secure than session cookies?
Neither is inherently more secure. JWTs provide stateless scalability but increase XSS attack surface if stored in localStorage. Session cookies provide automatic CSRF protection and easy revocation but require server-side storage. The security of either approach depends entirely on implementation—always use HTTPS, validate tokens properly, and follow OWASP guidelines.How long should a JWT be valid?
Access tokens should typically expire in 5-15 minutes for sensitive operations. Refresh tokens can last 7-30 days. The shorter the token lifetime, the smaller the window of opportunity for attackers who obtain the token. Always include an `exp` claim—never issue tokens without expiration.Can I encrypt a JWT to hide its payload?
Yes. JWE (JSON Web Encryption) encrypts the entire token, including the payload. Use JWE when you need to protect sensitive data in the token. However, JWE adds complexity and performance overhead. For most applications, simply avoiding sensitive data in the JWT payload and using HTTPS is sufficient.What happens if I forget to verify the JWT signature?
If you skip signature verification, the token is completely untrusted. Any attacker can modify the payload claims (e.g., change `"role": "user"` to `"role": "admin"`) and the server will accept the tampered token as valid. Always verify the signature before trusting any JWT claims.Should I use HS256 or RS256?
Use HS256 (HMAC) for single-server or monolithic applications where simplicity and performance are priorities. Use RS256 (RSA) or ES256 (ECDSA) for microservices, third-party API integrations, or any scenario where multiple independent services need to verify tokens. You can generate signing keys with our [Password Generator](/password-generator).How do I securely store JWTs on the client?
Avoid `localStorage` and `sessionStorage`—both are accessible via JavaScript, making them vulnerable to XSS attacks. The safest approach is to use `HttpOnly`, `Secure`, `SameSite=Strict` cookies, which prevent JavaScript access entirely. For SPAs, consider the BFF (Backend-for-Frontend) pattern where the server manages tokens in HttpOnly cookies.About the Author
The GeneratePass Editorial Team builds privacy-first security tools that run entirely in your browser. Every tool on GeneratePass processes data locally — nothing is ever sent to a server. Visit generatepass.me to try our free Password Generator, Entropy Calculator, and Breach Checker.
GeneratePass Developers
Verified AuthorSecurity researchers, cryptography engineers, and software developers dedicated to making browser-based cryptographic tools accessible and secure. We write guides with a focus on local execution, zero-trust patterns, and client-side data sovereignty.
Related Security Tools
Related Publications
Base64 Encoding Explained
A technical guide to Base64 encoding, explaining the mathematical bit-shifting process, padding logic, and modern use cases in web applications.
Base64 Myths Debunked: What Encoding Actually Does (and Doesn't Do)
Debunking the most common Base64 myths, explaining what Base64 encoding is, what it is not, and when you should—and shouldn't—use it.
MD5 Security Problems: Why You Should Never Use It
Learn why MD5 is broken, how collision attacks work, and what to use instead. A complete guide to MD5 vulnerabilities and modern alternatives.