"Should I use OAuth 2.0 or JWT for my new project?" is one of the most common questions asked by developers. But comparing OAuth and JWT directly is comparing apples to oranges: OAuth is an authorization protocol, while JWT is a token data format.
In modern web architectures, they are not competitors—they are partners. OAuth 2.0 defines the handshake, roles, and grant flows, and it often uses JSON Web Tokens as the physical carrier for its credentials. Let's break down the mechanics.
1. Demystifying the Concepts: The Car and the Engine
To understand the distinction clearly, think of an analogy:
🔄 OAuth 2.0 Token Handshake & JWT Bearer Architecture
Protocol Flow- OAuth 2.0 is like the Postal Delivery Service protocol: It defines who sender and recipient are, which mailbox requires a key, what forms must be signed, and who is authorized to pick up packages.
- JWT is the sealed, tamper-evident envelope: It is the physical standardized format containing the letter, complete with a wax seal that verifies nobody opened or forged it along the way.
💡 The Key Takeaway
You do not pick between OAuth and JWT. You choose whether you need an authorization framework (OAuth 2.0), and then you decide whether your access tokens will be formatted as opaque strings or JSON Web Tokens (JWT).
2. What Is OAuth 2.0? (RFC 6749)
OAuth 2.0 is an open standard authorization framework specified in RFC 6749. It enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner or by allowing the third-party application to obtain access on its own behalf.
OAuth defines four distinct roles:
- Resource Owner: The user who owns the data (e.g., you, the Google account holder).
- Client: The application attempting to access the user's data (e.g., a Spotify app accessing your Google contacts).
- Authorization Server: The server that authenticates the user and issues access tokens (e.g.,
accounts.google.com). - Resource Server: The API hosting the protected resources (e.g.,
contacts.googleapis.com).
3. What Is a JWT? (RFC 7519)
JSON Web Token is an open standard (RFC 7519) defining a compact, URL-safe means of representing claims securely between two parties. It consists of three parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRGV2ZWxvcGVyIn0.4S...
- Header: Algorithm and token type (e.g.,
{"alg": "RS256", "typ": "JWT"}). - Payload: The claims or statement of facts (e.g.,
{"sub": "usr_99", "scope": "read:profile"}). - Signature: Cryptographic hash verifying authenticity and tamper resistance.
4. How OAuth 2.0 Uses JWTs
When an authorization server completes an OAuth grant flow (such as Authorization Code with PKCE), it must issue an Access Token to the client. The OAuth 2.0 specification deliberately does not mandate what an access token looks like—it only requires that it can authorize access.
Authorization servers have two choices for access token implementation:
| Feature | Opaque Access Token (By Reference) | JWT Access Token (By Value) |
|---|---|---|
| Representation | Random string: v9x_k81mQ92zP... |
Signed Base64URL JSON: header.payload.sig |
| Validation Method | Resource server calls Auth Server Introspection endpoint (RFC 7662) | Resource server validates cryptographic signature locally using Auth Server's public key |
| Latency Overhead | 1 HTTP roundtrip to Auth Server on every API request | Zero network latency; purely local CPU validation |
| Revocation | Instant: Auth server marks token invalid in database | Delayed until token expires (requires blocklist or short TTL) |
| Information Leakage | Zero: token contains no data to the naked eye | Claims can be decoded and read by anyone with the token |
5. Complete Flow: OAuth 2.0 Authorization Code Flow with JWT
Here is how OAuth 2.0 and JWT combine in modern web applications (like single-page applications and mobile apps using PKCE):
SPA Frontend Auth Server (e.g. Auth0/Okta) API Gateway
| | |
|--- 1. Redirect to /authorize ----->| |
| (client_id, scope, code_challenge)| |
| | |
| [User Logs In & Grants Consent] | |
|<-- 2. Redirect back with code -----| |
| | |
|--- 3. POST /oauth/token ---------->| |
| (code + code_verifier) |--+ 4. Validate PKCE verifier |
| | | Mint Access Token (JWT) |
| | | Mint ID Token (JWT) |
|<-- 5. Return Tokens ---------------|<-+ |
| |
|=== API REQUEST WITH JWT BEARER TOKEN ===============================|
|--- 6. GET /api/orders --------------------------------------------->|
| Authorization: Bearer |
| |--+ 7. Fetch JWKS Public Keys |
| | | (Cached locally) |
| |<-+ |
| |--+ 8. Verify JWT Signature |
| | | Verify aud: "api.store" |
| | | Check scope: "read:order"|
| |<-+ |
|<-- 9. HTTP 200 Protected Orders Data -------------------------------|
6. Scopes vs. Roles in JWT Payloads
A frequent anti-pattern is confusing OAuth scopes with user roles:
- OAuth Scopes (Client Delegated Permissions): Scope represents what permissions the user granted to the client application. For instance,
scope: "read:profile write:status". It limits the client application's blast radius. - User Roles / Permissions: Role represents what the authenticated user is actually allowed to perform in the business domain. For instance,
roles: ["admin", "billing_manager"].
An effective API checks both: Is the user an administrator, AND did the user grant the admin:write scope to the specific client app making the call?
7. Practical Summary
- Use OAuth 2.0 when you need delegated authorization, single sign-on across separate applications, or third-party API access.
- Use JWT as the format for your OAuth 2.0 access and ID tokens to enable zero-lookup, high-speed cryptographic verification at your API gateways and microservices.
- If you simply have a monolithic web application with a single frontend and backend, you don't need the complexity of OAuth 2.0; straightforward session cookies or simple JWT authentication will suffice.