"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
Resource Owner (End User / Browser) Client Application SPA / Mobile App Auth0 / IdP Server Issues Signed JWT API / Resource Server Verifies JWT Locally 1. User Authenticates & Grants Scope Consent 2. JWT Authorization: Bearer <jwt> OAuth 2.0 = The Protocol JWT = The Token Format
Figure 1: OAuth 2.0 specifies the authorization dance and scope grant flow; JWT is the signed data format carrying the resulting user permissions.

💡 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:

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

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):

OAuth 2.0 Authorization Code Flow with PKCE using JWT
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:

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