JSON Web Tokens (JWT) are ubiquitous across modern web architectures, single-page applications, and zero-trust microservice meshes. Yet, security audits routinely uncover critical vulnerabilities: using symmetric secrets susceptible to brute-forcing, storing tokens in accessible localStorage, and failing to validate token expiration timestamps.
1. The Anatomy of an RFC 7519 JWT
A JWT consists of three Base64URL-encoded strings concatenated by periods (header.payload.signature):
- Header: Specifies token type (
JWT) and cryptographic signing algorithm (RS256,EdDSA, orHS256). - Payload (Claims): Contains registered claims (
sub,exp,iat,iss) and application identity data (user ID, tenant, roles). - Signature: Cryptographic hash or signature proving the header and payload were not tampered with in transit.
2. Symmetric (HS256) vs Asymmetric (RS256 / Ed25519)
Choosing the appropriate signature algorithm dictates your architectural security boundary:
- HMAC-SHA256 (HS256): Uses a shared secret key for both signing and verifying. If any downstream microservice needs to verify the token, it must possess the shared secret. If a single microservice is compromised, attackers can forge arbitrary valid tokens for any user.
- RSA-SHA256 (RS256) & EdDSA (Recommended): Uses a private key held exclusively by the central Authentication Authority (Auth0, Keycloak, or custom OAuth provider) to sign tokens, while exposing a public JSON Web Key Set (JWKS) to microservices. Resource servers can verify signatures without possessing the ability to forge tokens.
3. Where to Store Tokens: LocalStorage vs HttpOnly Cookies
Storing access tokens in browser storage is one of the most critical decisions in frontend architecture:
- LocalStorage / SessionStorage (Dangerous): Any Cross-Site Scripting (XSS) vulnerability or compromised third-party npm package can read
localStorage.getItem('token')and exfiltrate user credentials to a remote server. - HttpOnly, SameSite=Strict Cookies (Recommended): Cookies marked with the
HttpOnlyattribute cannot be accessed by client-side JavaScript, neutralizing token theft via XSS. Paired withSameSite=StrictandSecureflags, this completely mitigates Cross-Site Request Forgery (CSRF).
4. Defending Against the Critical "none" Algorithm Exploit
RFC 7519 defines an algorithm named none for unsigned debugging tokens. Flawed verification libraries accepted tokens with {"alg": "none"} and an empty signature, allowing attackers to modify the payload to grant themselves administrator privileges.
// In Node.js / Express: Always specify an explicit algorithms whitelist!
const jwt = require('jsonwebtoken');
// INSECURE: Accepts whatever algorithm the client specified in the header
jwt.verify(token, secret);
// SECURE: Enforces asymmetric RS256 algorithm verification
jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.prowebtools.online/',
audience: 'https://api.prowebtools.online/'
});
5. Token Lifecycles: Short-Lived Access + Refresh Tokens
Because stateless JWTs cannot be trivially revoked without querying a central database, access tokens must have short lifespans:
- Access Tokens: 5 to 15 minutes lifetime (
exp = iat + 900). Limits the window of vulnerability if a token is intercepted. - Refresh Tokens: 7 to 30 days lifetime, stored in a partitioned database table and delivered via strict
httpOnlycookie. Rotated upon every refresh request (Refresh Token Rotation).
6. Interactive Auth & Cryptography Utilities
- JWT Debugger & Payload Inspector - Decode headers, claims, and verify timestamps 100% in-browser with zero server logging.
- SHA-256 Hash Generator - Compute cryptographic digests with WebCrypto API.
- Strong Password & Secret Generator - Generate high-entropy 256-bit cryptographically secure strings.
- SSH & Asymmetric Keys Cheat Sheet - RSA and Ed25519 key generation commands.