GeneratePass
Cryptography 14 min read

JWT Security Guide: How JSON Web Tokens Work and How to Secure Them

By GeneratePass Developers | Published: July 08, 2026 | Last Updated: July 08, 2026

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:

  1. 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.

  2. 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

SegmentContentEncodingPurposeTamper-Proof?
HeaderAlgorithm and token typeBase64urlIdentifies signing methodNo (readable by anyone)
PayloadClaims and user dataBase64urlCarries identity and permissionsNo (readable by anyone)
SignatureCryptographic hashBinaryVerifies integrityYes (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:

  1. The server generates a strong secret key (e.g., HS256 uses a 256-bit key).
  2. When issuing a token, the server computes HMAC-SHA256(header + payload, secret).
  3. 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:

AlgorithmKey SizeHash FunctionSecurity Level
HS256256 bitsSHA-256Strong (recommended)
HS384384 bitsSHA-384Very strong
HS512512 bitsSHA-512Very 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:

  1. The server keeps the private key secret.
  2. The public key is distributed to services that need to verify tokens.
  3. When issuing, the server signs with the private key.
  4. 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:

AlgorithmKey TypeCurve/SizeSecurity Level
RS256RSA2048+ bitsStrong
RS384RSA3072+ bitsVery strong
RS512RSA4096+ bitsVery strong
ES256ECDSAP-256 curveStrong (smaller keys)
ES384ECDSAP-384 curveVery strong
ES512ECDSAP-521 curveVery strong
EdDSAEdDSAEd25519Strong (fastest)

When to Choose HMAC vs. RSA/ECDSA

ScenarioRecommended AlgorithmReason
Single server, monolithic appHMAC (HS256)Fast, simple, one secret
Microservices (3+ services)RSA (RS256) or ECDSA (ES256)Public key distribution
High-performance API gatewayHMAC (HS256)Lowest latency
Third-party API authenticationRSA (RS256)Industry standard
Mobile app backendES256Small 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:

  1. Attacker takes a valid JWT.
  2. Changes the header "alg" from "HS256" to "none".
  3. Removes the signature.
  4. 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:

  1. Attacker obtains the server’s RSA public key.
  2. Creates a token signed with HMAC-SHA256 using the RSA public key as the HMAC secret.
  3. Changes the header "alg" from "RS256" to "HS256".
  4. 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, or SameSite flags

Safer alternatives:

  • HttpOnly cookies (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 TypeRecommended ExpirationUse Case
Access Token5-15 minutesAPI requests
ID Token1-24 hoursUser identity
Refresh Token7-30 daysToken renewal
Service Token1-60 minutesInter-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 expired
  • nbf: Token is not used before its valid time
  • iss: Token was issued by the expected authority
  • aud: Token is intended for your API
  • sub: 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

FactorJWT (Stateless)Session Cookies (Stateful)
Server StorageNo session data storedSession data stored in memory/DB
ScalabilityExcellent (no shared state)Requires shared session store
RevocationDifficult (requires denylist)Easy (delete session from store)
XSS RiskHigh (if in localStorage)Lower (HttpOnly cookies)
CSRF RiskLow (not automatically sent)Higher (cookies auto-sent)
Mobile SupportExcellentComplex (cookies vary by platform)
Payload SizeLarge (contains claims)Small (session ID only)
Cross-DomainEasy (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 Author

Security 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.

Focus: Cryptography Standard: zero-trust