JWT vs OAuth Tokens: Understanding the Differences
The Confusion Is Common
"Should I use JWT or OAuth?" is a question that reveals a misunderstanding. JWT and OAuth are not alternatives to each other — they serve different purposes and often work together.
- JWT is a token format — a way to encode and sign data
- OAuth 2.0 is an authorization framework — a set of rules for granting access
Understanding this distinction prevents costly architectural mistakes.
What Is a JWT?
A JSON Web Token is a self-contained, signed token that carries claims about a subject. It has three parts — header, payload, and signature — and anyone with the signing key can verify its authenticity.
Key property: The token contains all the information needed to validate it. No database lookup required (for signature verification).
{
"sub": "user-42",
"role": "editor",
"exp": 1516242622
}
A JWT is like a passport: it contains identity information, a photograph, and a signature. The verifier checks the signature — not a central database.
What Is OAuth 2.0?
OAuth 2.0 is an authorization framework that defines how a client application can obtain limited access to a resource on behalf of a resource owner. It specifies several grant types (flows):
| Grant Type | Use Case |
|---|---|
| Authorization Code | Server-side web apps |
| Authorization Code + PKCE | Single-page apps, mobile apps |
| Client Credentials | Server-to-server communication |
| Device Code | IoT devices, CLI tools |
OAuth 2.0 tells you how to get a token and what to do with it. It does not mandate a specific token format — the token can be a JWT, an opaque string, or anything else.
Self-Contained vs Opaque Tokens
This is the core distinction that matters in practice.
Self-Contained Tokens (JWT)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0In0.Gfx6VO9tcxwk6xqx9yYzSfgfe
- Contains readable claims inside the token
- Verifiable without a database lookup (with the right key)
- Stateless by design
- Cannot be revoked before expiration (without extra infrastructure)
Opaque Tokens
a1b2c3d4-e5f6-7890-abcd-ef1234567890
- A random string with no embedded information
- Requires a database or cache lookup to validate
- Easily revokable — just delete the record
- Fully stateful
Comparison
| Property | JWT (Self-Contained) | Opaque Token |
|---|---|---|
| Contains claims | Yes | No |
| Needs DB lookup to verify | No | Yes |
| Revocable | Hard (needs blacklist) | Easy (delete record) |
| Size | Large (1–4 KB) | Small (32–64 bytes) |
| Verifiable offline | Yes (with public key) | No |
| Information leakage risk | Yes (payload readable) | No |
When to Use JWTs
JWTs excel when you need stateless verification and claims distribution.
Best Use Cases
- Microservices: Services verify tokens locally without calling a central auth service on every request
- Third-party APIs: The API consumer validates the token without calling your server
- Short-lived access tokens: 5–15 minute tokens where revocation is less critical
- Federated identity: Sharing identity claims across trust boundaries
Example: Microservices Architecture
Client → API Gateway (validates JWT) → Service A (reads claims from JWT)
→ Service B (reads claims from JWT)
→ Service C (reads claims from JWT)
No inter-service calls for authentication. Each service verifies the JWT independently.
When to Use Opaque Tokens
Opaque tokens are better when revocation and control are priorities.
Best Use Cases
- Internal applications: Single-server or single-service where DB lookups are cheap
- Long-lived sessions: Where you need to revoke access immediately
- High-security systems: Where token content must never be exposed
- Legacy systems: Where existing session infrastructure works
Example: Traditional Web App
Client → Server (validates opaque token against Redis) → Response
Simple, fast (Redis lookup <1ms), and tokens are revocable instantly.
The Hybrid Approach: The Best of Both
Most production systems use a combination of JWTs and opaque tokens:
Pattern: JWT Access Token + Opaque Refresh Token
| Token | Type | Lifetime | Storage | Purpose |
|---|---|---|---|---|
| Access Token | JWT | 5–15 min | Memory | Authorize API requests |
| Refresh Token | Opaque | 7–30 days | HttpOnly cookie | Obtain new access tokens |
How it works:
- User authenticates → server issues both tokens
- Client uses the JWT access token for API calls (stateless verification)
- When the JWT expires, client sends the opaque refresh token
- Server looks up the refresh token in the database → issues a new JWT + new refresh token
- If refresh token is compromised, delete the database record — immediate revocation
This gives you stateless API calls (fast, scalable) with revocable sessions (secure, controllable).
Pattern: Opaque Reference Token + JWT Internally
Some systems store a JWT in a database and give the client an opaque reference:
Client sends: abc123 (opaque reference)
Server looks up: abc123 → { JWT stored in DB }
Server validates JWT claims internally
This combines the secrecy of opaque tokens with the rich claims of JWTs, at the cost of a database lookup.
Token Size Comparison
Token size affects bandwidth, especially for mobile networks:
| Token Type | Typical Size | Impact |
|---|---|---|
| Opaque token | ~40 bytes | Minimal overhead |
| JWT (3 claims) | ~200 bytes | Moderate overhead |
| JWT (10+ claims) | ~1–4 KB | Significant overhead |
| JWT + headers | Add ~50 bytes | HTTP overhead |
Every API request includes the token in the Authorization header. A 2 KB JWT sent on 100 requests per page load adds 200 KB of overhead on mobile connections.
Practical tip: Keep JWT claims minimal. Only include what the resource server needs.
Common Mistakes
Mistake 1: Using JWTs as Session Replacements for Browser Apps
Storing a long-lived JWT in localStorage creates both XSS and revocation problems. For browser-based applications with a single backend, server-side sessions with cookies are simpler and more secure.
Mistake 2: Putting Everything in the JWT
{
"sub": "user-42",
"name": "John Doe",
"email": "john@example.com",
"address": "123 Main St",
"phone": "555-0100",
"permissions": ["read", "write", "delete", "admin"],
"department": "Engineering",
"manager": "Jane Smith"
}
This token is huge, leaks PII, and cannot be updated without reissuing. Use JWTs for identity — fetch detailed profile data from an API.
Mistake 3: Confusing OAuth Scopes with JWT Claims
OAuth scopes define what the client can do (e.g., read:reports). JWT claims define who the subject is (e.g., sub: user-42). They complement each other but are not the same thing.
Decision Framework
Use this rapid guide to choose:
| Scenario | Recommended Token |
|---|---|
| Microservices with many services | JWT (short-lived) |
| Single-server web app | Opaque + session |
| Third-party API access | JWT (RS256) |
| Mobile app backend | JWT access + opaque refresh |
| Real-time revocation needed | Opaque tokens |
| Server-to-server communication | JWT (Client Credentials) |
Summary
JWTs and OAuth tokens answer different questions:
- JWT answers "how do I encode and verify claims?"
- OAuth answers "how do I grant and manage access?"
In production, the most common and effective pattern combines both: use OAuth 2.0 flows to obtain tokens, issue short-lived JWTs for API access, and use opaque refresh tokens for session management.
Related Guides
Try It Yourself
Decode any JWT to inspect its claims and verify its structure using our free JWT Decoder. See what's inside your tokens — all processing happens locally in your browser.