
JWT vs Opaque Tokens: The Architecture of Trust
An examination of JWT and opaque token architectures, comparing introspection, revocation, and security trade-offs for backend systems.
When designing authentication systems, backend developers often face a binary choice between two token formats: JSON Web Tokens (JWT) and opaque reference tokens. While both serve to validate identity, they operate on fundamentally different mechanisms regarding state, revocation, and security boundaries. Understanding these mechanisms is critical for selecting the right architecture for your backend systems.
The Core Mechanism: Self-Contained vs. Reference
The primary difference lies in where the identity information resides and how it is validated.
JWT: The Self-Contained Assertion
A JWT is a self-contained, signed JSON object as defined in RFC 7519. It contains claims (data about the user) directly within the token payload. Validation is stateless: the server verifies the cryptographic signature using a shared secret (HMAC) or a public key (RSA/ECDSA). If the signature is valid and the token has not expired, the server trusts the claims inside.
Mechanism:
- Client Request: Sends
Authorization: Bearer <jwt_token>. - Server Validation:
- Decodes the header to find the algorithm (
alg) and key ID (kid). - Retrieves the corresponding public key or secret.
- Cryptographically verifies the signature over the
header.payloadportion. - Checks standard claims like
exp(expiration) andiss(issuer).
- Decodes the header to find the algorithm (
- Outcome: If valid, the server extracts the user ID from the payload and proceeds. No database lookup is required for identity validation.
// Example JWT Payload (base64url decoded)
{
"sub": "user_123",
"name": "Alice",
"iat": 1678886400,
"exp": 1678890000
}Opaque Token: The Reference Pointer
An opaque token is a random string with no inherent meaning or structure. It acts as a pointer or reference to user data stored securely in the authorization server’s backend (e.g., Redis, SQL database). Validation is stateful: the server must look up the token to verify its validity and retrieve associated claims, typically via an introspection endpoint as specified in RFC 7662.
Mechanism:
- Client Request: Sends
Authorization: Bearer <opaque_token>. - Server Validation:
- Sends the token to an introspection endpoint (or looks it up locally if the resource server shares the store).
- The Authorization Server checks if the token exists, is active, and has not expired.
- Returns the associated claims (e.g.,
active: true,scope: "read:users",sub: "user_123").
- Outcome: The resource server trusts the introspection response. The actual user data never leaves the secure boundary of the Authorization Server.
POST /oauth2/introspect HTTP/1.1
Content-Type: application/x-www-form-urlencoded
token=<opaque_token_value>&token_type_hint=access_tokenRevocation: The State Management Dilemma
Revocation is where the architectural trade-offs become most apparent.
JWT Revocation: The Blocklist Problem
Since JWTs are self-contained and stateless, there is no built-in way to "delete" a token once issued. To revoke a JWT, you must implement external state management.
- Blocklist Approach: Maintain a list of revoked JWT JTI (JWT ID) values in a fast key-value store like Redis. On every request, check if the JWT’s JTI is in the blocklist. This adds latency to every request and requires cleanup jobs to remove old entries. The JTI claim is defined in RFC 7519 specifically to support such scenarios, though the mechanism for checking it is left to the implementation.
- Short-Lived Tokens: Issue JWTs with very short lifespans (e.g., 5-15 minutes). This reduces the window of opportunity for an attacker but increases the complexity of token refresh flows.
Opaque Token Revocation: Immediate Invalidation
Opaque tokens simplify revocation because the token is merely a key to a database record.
- Deletion: To revoke a token, simply delete the corresponding record from the database or Redis.
- Immediate Effect: The next time the client presents the token, the introspection lookup fails, and access is denied. No blocklist checks are needed during validation.
This makes opaque tokens preferable for applications requiring strict security compliance where immediate session termination is critical (e.g., banking, healthcare).
Security and Privacy Trade-offs
Data Exposure
- JWT: The payload is base64-encoded, not encrypted (unless JWE is used). Any party with the token can read the claims. This is safe for non-sensitive data (user ID, roles) but dangerous for sensitive data (email, SSN) unless the transport layer (TLS) is trusted and the payload is encrypted using RFC 7516 (JSON Web Encryption).
- Opaque Tokens: The payload never travels to the client. Sensitive data remains on the Authorization Server. The client only holds a random string. This minimizes the attack surface for data leakage via logs, browser history, or XSS attacks.
Attack Surface
- JWT: The resource server must have access to the signing key (or public key). If the resource server is compromised, attackers can forge valid tokens. The validation logic is complex and prone to implementation errors, such as the critical vulnerability of accepting
alg: nonewhich bypasses signature verification entirely. - Opaque Tokens: The introspection endpoint is a new attack vector. If the Authorization Server is down, resource servers cannot validate tokens. This introduces a single point of failure and additional network latency for every authenticated request.
Choosing the Right Design
| Feature | JWT (Self-Contained) | Opaque Token (Reference) |
|---|---|---|
| Validation | Stateless, cryptographic | Stateful, database lookup |
| Revocation | Complex (blocklist/short TTL) | Simple (delete record) |
| Payload | Visible to client (signed) | Hidden from client |
| Latency | Low (no DB call) | Higher (introspection call) |
| Best For | Microservices, high scale, public APIs | Enterprise apps, strict security, internal services |
Conclusion
There is no universally superior choice. Use JWTs when you need high performance, low latency, and decentralized validation across many microservices, and when you can tolerate the complexity of revocation. Use opaque tokens when security, privacy, and immediate revocation are paramount, and you can absorb the latency of introspection calls.
Many modern systems adopt a hybrid approach: use short-lived opaque tokens for the initial handshake, then issue JWTs for subsequent requests within the same session. This balances the security benefits of opaque tokens with the performance benefits of JWTs.
Common Pitfalls
When implementing either architecture, developers frequently make critical errors that compromise security or performance.
- Storing Sensitive Data in JWTs: Never store PII (Personally Identifiable Information), passwords, or secrets in JWT payloads. Even with signatures, the data is readable by anyone who intercepts the token unless encrypted via JWE.
- Failing to Rotate Signing Keys: If a private key is compromised, an attacker can forge valid tokens signed with it. Implement key rotation strategies and ensure resource servers can handle multiple active public keys during transition periods.
- Ignoring Introspection Endpoint Failures: In opaque token systems, treating the introspection call as optional or caching invalid tokens leads to security holes. Always handle timeouts and failures gracefully, typically by denying access rather than falling back to a cached or assumed-valid state.
- Algorithm Confusion Attacks: When validating JWTs, strictly enforce the expected
algheader value. Do not rely on the client to specify the algorithm, as this can lead to signature bypass vulnerabilities.
Practical Takeaways
- Decide on State First: If your system requires immediate revocation or strict auditability of active sessions, start with opaque tokens.
- Evaluate Latency Tolerance: If your microservices architecture cannot afford the network overhead of an introspection call per request, JWTs provide necessary performance gains.
- Minimize Payload Size: For JWTs, keep claims minimal. Store complex user data in the database and reference it via the JWT's
suborjticlaim. - Implement Key Rotation: Regardless of token type, have a plan for rotating signing keys or revoking compromised credentials.
- Secure Transport: Always use TLS for token transmission. For JWTs, consider JWE if tokens traverse untrusted networks or are stored in client-side storage.
Related posts
How to Revoke a JWT: Denylist & Expiry Strategies
Learn how to revoke a JWT you already issued using denylists and token invalidation strategies for secure backend authentication.
mTLS vs JWT for Service-to-Service Auth
A comparison of mTLS and JWT for service-to-service authentication, examining transport-level security versus request-level identity in modern architectures.
API Gateway OIDC: Kong and Friends
Implement OIDC authentication in Kong API Gateway, covering JWT validation, JWKS caching, and upstream header propagation.