OAuth vs JWT: A Format vs a Flow (and Why You Probably Use Both)

OAuth vs JWT is the wrong comparison — they're not even the same kind of thing. A JWT is a token FORMAT: a tamper-proof, self-contained ID card the server verifies by signature, no database lookup. OAuth is a delegation PROTOCOL: how an app gets permission to access your data in another app without ever seeing your password. Here's how they actually differ — with code — and why an OAuth flow usually hands back a token that's a JWT.

Banner

Prefer to watch? ▶ OAuth vs JWT in 90 seconds ✈ Telegram

"Should I use OAuth or JWT?" gets asked in interviews, on Stack Overflow, and in design reviews constantly — and it's a bit of a trick question. The honest answer is that they're not competing options. One is a kind of token. The other is a way to hand out tokens. You can use either without the other, and most real systems use both at once.

So before you pick, get the categories straight:

  • JWT is a token FORMAT — a specific, self-contained way to shape a token so anyone holding the signing key can trust it.
  • OAuth is a delegation PROTOCOL — a defined flow for letting one app access your data in another app without ever seeing your password.

A format vs a flow. Once that clicks, the "vs" mostly dissolves.


JWT: a tamper-proof ID card you carry

A JSON Web Token is a string in three base64url-encoded parts joined by dots:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ.K3v9-Hs...
└──── header ────┘ └──────── payload ────────┘ └─ signature ─┘
  • Header — the algorithm (e.g. HS256 or RS256).
  • Payload — the claims: who the user is (sub), when it expires (exp), and whatever else you put there (role, email).
  • Signature — the header + payload, signed with a secret (HMAC) or a private key (RSA/EC).

The magic is in that signature. When a request arrives carrying the token, the server doesn't look anything up — it just re-computes the signature and checks it matches. If it does, the claims are trustworthy; if a single byte of the payload was tampered with, the signature breaks. That's what "stateless" means: the trust travels inside the token, so no session table, no Redis, no DB round-trip per request.

import jwt  # PyJWT

SECRET = "super-secret-key"

# issue a token at login
token = jwt.encode({"sub": "123", "role": "admin"}, SECRET, algorithm="HS256")

# verify it on every request — no DB lookup
claims = jwt.decode(token, SECRET, algorithms=["HS256"])  # raises if tampered/expired
print(claims["sub"], claims["role"])   # 123 admin

Two things people get wrong: a JWT is signed, not encrypted — anyone can base64-decode the payload and read it, so never put secrets in it. And because it's self-contained, you can't easily un-issue one before it expires — which is why JWTs are kept short-lived and paired with refresh tokens.

That's the whole of JWT. Notice what we haven't talked about yet: how the user got the token in the first place. That's a different question — and it's where OAuth lives.


OAuth: a valet key for delegated access

OAuth 2.0 answers a question JWT never touches: how does one app get permission to act on your behalf in another app — without you handing over your password?

The classic example is "Log in with Google." A new app wants your email and basic profile. The bad old way would be to type your Google password into that app (now it has full access to your account, forever). OAuth replaces that with a valet key:

  1. The app redirects you to Google.
  2. Google authenticates you (the app never sees your password) and asks: "Allow this app to see your email and profile?"
  3. You approve. Google redirects back with a short authorization code.
  4. The app exchanges that code (plus its own secret) for an access token — a key scoped to only email + profile, and revocable at any time.
  5. The app calls Google's API with that token to fetch your data.
You ──▶ App ──▶ Google (you log in + consent)
                  │
                  ▼
          authorization code ──▶ App exchanges for ──▶ access token (scoped, revocable)
                                                              │
                                                              ▼
                                                  App calls API on your behalf

The point of OAuth is scoped, revocable delegation: the third-party app gets a limited key, never your credentials, and you (or Google) can revoke it without changing your password. (When you also want to know who the user is, you add OpenID Connect on top of OAuth — and it returns an ID token, which is... a JWT.)


So where's the "vs"?

There isn't one — they answer different questions:

JWTOAuth 2.0
What it isA token formatA delegation protocol (a flow)
Question it answers"What shape is the token, and how do I trust it?""How does an app get a token at all, without my password?"
Verifies byChecking a signature (no lookup)N/A — it's a flow, not a token
Hands youA self-contained signed stringAn access token (often a JWT)
RevocationHard (short TTL + refresh tokens)First-class (revoke the grant)
Use it whenYou own client + server, need stateless loginA third party needs delegated access

And the kicker that most "OAuth vs JWT" arguments miss: they usually work together. An OAuth flow ends by handing the app an access token — and that token is very often a JWT. It was never OAuth or JWT; it's OAuth the protocol carrying JWT the format.


Which should you reach for?

  • Reach for a plain JWT when you own both the client and the server and just need stateless login — your SPA or mobile app talks to your own API, you issue a short-lived JWT at login, verify it by signature on each request, and refresh it when it expires. No third party involved.
  • Reach for OAuth when a third party needs delegated access — "Log in with Google/GitHub," letting one of your services call another on a user's behalf, or letting an external app touch your users' data. You want scoped, revocable grants and you never want passwords flowing through the wrong place.
  • Most real systems use both: an OAuth/OpenID Connect flow to get a token, and JWTs as the format of the access/ID tokens that flow hands back, with short-lived JWTs + refresh tokens to balance statelessness against revocation.

So the next time someone asks "OAuth or JWT?", the senior answer is: "Those aren't alternatives. JWT is the token format; OAuth is how you'd hand one out to a third party. What are you actually trying to do — log users into your own app, or let another app act on their behalf?"

Want the 90-second visual version? Watch the reel.

OAuth vs JWT: A Format vs a Flow (and Why You Probably Use Both) | Vahid Aghajani