Join our Newsletter — 33% off our NHI Course
Home› Guides› JWT vs OAuth: how a token format and…
Guide Web & API Security

JWT vs OAuth: how a token format and an authorisation framework fit together

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 16 min read
On this page

"Should we use JWT or OAuth?" is a category error, and APIs designed around it end up with home-grown login tokens, ID tokens accepted as access tokens and no way to revoke anything. JWT (RFC 7519) is a format for carrying signed or encrypted claims. OAuth 2.0 (RFC 6749) is a framework for a client to obtain limited, delegated access to an API. They operate at different layers, they are often used together, and each is also used without the other. This guide is for API architects, developers and security reviewers who need to choose a design, review one, or explain to a team why "we use JWT" does not answer how an API is authorised. Token format trade-offs and deep JWT hardening are covered in the JWT vs Opaque Tokens and JWT Security Guide pages; this one is about where the two meet and where they are confused.

Key takeaways

  • Different layers, not alternatives. JWT defines what a token looks like; OAuth defines who issues tokens to whom, for which resource and with what consent. An OAuth access token may be a JWT, or may not.
  • Neither one is authentication. A valid JWT proves that an issuer signed some claims; OAuth proves a client was granted access. User authentication for clients comes from OpenID Connect, whose ID Token is a JWT with strict validation rules.
  • RFC 9068 is the bridge. When OAuth access tokens are JWTs, RFC 9068 fixes the header type (at+jwt), seven required claims and the validation steps a resource server must run.
  • Most real failures are confusion failures. ID tokens used to call APIs, tokens for one audience accepted by another, and session JWTs with no expiry all come from treating "a signed JWT" as sufficient.
  • API keys still fit some jobs. Simple server-to-server metering and low-risk public data can justify keys; delegated user access, third-party clients and fine-grained scopes need OAuth.

The short answer

Use OAuth 2.0 (with OpenID Connect where clients need to know who the user is) to decide how clients obtain tokens. Then decide the access token format: a JWT validated locally under RFC 9068, or an opaque reference validated by introspection. Use JWTs outside OAuth only where a standard profile defines them, such as OAuth client authentication assertions (RFC 7523) or OpenID Connect ID Tokens, and avoid inventing your own JWT login scheme. If someone asks "JWT or OAuth?", the useful answer is "OAuth for the flow, and here is why we chose this token format inside it".

Category confusion: what each standard actually defines

StandardWhat it isWhat it definesWhat it leaves out
JWT, RFC 7519Token formatA compact, URL-safe way to represent claims, encoded as a JWS (signed or MACed) or JWE (encrypted); seven registered claims (iss, sub, aud, exp, nbf, iat, jti), all optionalWhich claims are required, who issues tokens, how they are obtained, how they are revoked. RFC 7519 says the claims an application needs are outside its scope
OAuth 2.0, RFC 6749Authorisation frameworkRoles (resource owner, client, authorisation server, resource server), grants, token endpoint, scopesThe access token format. Section 1.4 says access tokens can have different formats, structures and methods of utilisation
Bearer usage, RFC 6750Token presentationAuthorization: Bearer header, error codes invalid_token (401) and insufficient_scope (403)Token contents
JWT access token profile, RFC 9068OAuth profile for JWT access tokenstyp at+jwt, required claims iss, exp, aud, sub, client_id, iat, jti, resource server validation stepsWhether you must use JWTs at all: OAuth still mandates no format
OpenID Connect Core 1.0Identity layer on OAuth 2.0The openid scope, the ID Token (a JWT about the authentication event), UserInfoAPI authorisation decisions
JWT BCP, RFC 8725 (BCP 225)Implementation guidanceThreats and practices for anyone producing or consuming JWTsFlows and grants

The confusion has a cause. Many identity providers issue JWT access tokens by default, and many tutorials show a login endpoint that returns a JWT. Teams then conclude that JWT is a login method. It is not: the OWASP API Security Top 10 2023 entry API2 Broken Authentication states plainly that OAuth is not authentication, and neither are API keys, and it lists accepting unsigned JWTs ({"alg":"none"}) and not validating expiry as signs of a broken API.

Where JWTs appear in and around OAuth

Token or assertionDefined byWho creates itWho validates itKey validation point
JWT access tokenRFC 9068Authorisation serverResource server (API)typ at+jwt, aud contains the API's identifier, iss exact match
ID TokenOpenID Connect CoreOpenID ProviderClient (relying party) onlyaud contains the client's client_id; nonce matches when sent
Client assertionRFC 7523 (client_assertion_type urn:ietf:params:oauth:client-assertion-type:jwt-bearer)OAuth clientAuthorisation serversub equals client_id, aud identifies the authorisation server, short exp
JWT authorisation grantRFC 7523 (grant type urn:ietf:params:oauth:grant-type:jwt-bearer)A trusted issuer or the clientAuthorisation serverTrusted issuer, audience, expiry, replay policy
Self-issued session JWTNo OAuth standardYour own login serviceYour own APIsWhatever you wrote: this is where most bespoke flaws live

The table matters because each row has a different intended audience. RFC 8725 calls the misuse of a token issued for one purpose in another context cross-JWT confusion, and recommends explicit typing and mutually exclusive validation rules (distinct typ values, claims, keys, audiences or issuers) so that one kind of JWT can never pass validation as another. For client assertions in depth, see the JWT Client Authentication (private_key_jwt) Guide; for the cross-app variant of the JWT grant, see the Identity Assertion JWT Authorization Grant (Cross-App Access) Guide.

Is JWT authentication?

No. Verifying a JWT signature authenticates the token's issuer and integrity, not the person or workload presenting it. Most JWT access tokens are bearer tokens: RFC 6750 describes a bearer token as usable by any party in possession of it, without proof of a key. So "the request carried a valid JWT" means "someone holds a token the issuer signed", which is why sender constraint (DPoP or mutual TLS) exists. See the DPoP Guide.

What authenticates the user to a client is OpenID Connect. Its core specification calls it a simple identity layer on top of OAuth 2.0: the client requests the openid scope and receives an ID Token, a JWT whose aud must contain the client's own client_id. That last rule is the practical line between authentication and authorisation. An ID Token tells the client who signed in; it is not addressed to your API and must not be sent to one as an access token. The relationship is covered further in OAuth 2.0 vs OIDC.

Two threat models: OAuth without JWT, and JWT without OAuth

OAuth with opaque access tokens

  • Architecture in words: the authorisation server issues a random reference; the API (or its gateway) asks the introspection endpoint what the token means and caches the answer briefly.
  • Threat model: token theft and replay, introspection endpoint abuse or outage, over-broad scopes granted at consent time.
  • Failure modes: APIs that skip introspection under load, caches that outlive revocation, an introspection endpoint reachable without client authentication.
  • Controls: authenticated introspection, cache lifetimes set per API risk, audience-restricted tokens, short lifetimes with refresh token rotation. See the OAuth Token Introspection and Revocation Guide.

JWT used without OAuth

  • Architecture in words: a login endpoint checks a password and returns a JWT signed with a shared secret; every API validates it with the same secret and trusts its claims.
  • Threat model: forged tokens through weak HMAC secrets or algorithm confusion, tokens that never expire, no revocation, no audience, no client identity, no consent for third-party access.
  • Failure modes: RFC 8725 lists weak symmetric keys open to offline brute force and RSA-to-HMAC algorithm confusion among JWT threats; a single shared HMAC secret also means every API that can verify tokens can mint them.
  • Controls: if you must, use asymmetric signing, an algorithm allowlist, explicit typ, aud per API, short exp and a server-side session or deny list for logout. In most cases a standard session cookie for first-party web apps, or an OAuth authorisation server, is simpler and safer. See Session Cookies vs Bearer Tokens.

OAuth with JWT access tokens (RFC 9068)

  • Architecture in words: the authorisation server signs access tokens with keys published as a JWKS; APIs validate locally without a network call per request.
  • Threat model: signing key compromise, validation shortcuts in API code, claims disclosure to clients, revocation lag until exp.
  • Controls: the RFC 9068 section 4 checks, RS256 support (mandatory under the profile) or stronger asymmetric algorithms, key rotation, short lifetimes. See the JSON Web Key Sets (JWKS) and Signing Key Rotation Guide.

Validation pitfalls where JWT and OAuth meet

PitfallWhat goes wrongControlSource
ID Token accepted as an access tokenA client sends its ID Token to the API; the API checks only the signature and issuer, both validRequire typ at+jwt and reject other values; require aud to contain the API identifier, not a client_idRFC 9068 s2.1 and s4; OIDC Core
Missing audience checkA token issued for API A is replayed at API B by anyone who obtained it (substitution)Each API checks aud contains its own identifierRFC 8725; RFC 9068 s4
Algorithm taken from the tokenalg none accepted, or an RSA public key used as an HMAC secretLibrary configured with an explicit algorithm allowlist; one algorithm per keyRFC 8725 s3.1; RFC 9068 s4
Untrusted key locationjku or x5u headers point the validator at attacker keys; kid used unsanitised in a lookupResolve keys only from the configured issuer's JWKS; allowlist key URLs; sanitise kidRFC 8725
Scope ignoredAny valid token for the API can call any endpointMap scopes to routes; return insufficient_scope (403)RFC 6750 s3
Client reading the access tokenClient logic depends on claims and breaks when the format changes, or leaks themTreat access tokens as opaque in clients; get user data from the ID Token or UserInfoRFC 9068 s6
No expiry or very long expiryStolen tokens work for days or foreverexp required and checked; lifetimes in minutes for JWT access tokensRFC 9068 s2.2; RFC 6750 s5.3; OWASP API2:2023

Specific error handling and troubleshooting for these checks are in the JWT Validation Errors Troubleshooting Guide.

When API keys still fit

API keys are a third option that teams weigh against "JWT or OAuth", and sometimes they are the right one. A key identifies a calling application or account; it carries no user, no delegated consent and usually no expiry unless you add one.

SituationAPI keyOAuth access token (JWT or opaque)
Metering a server-side integration to low-risk or public dataFits, with rate limits, IP or network restrictions and rotationWorks but may be heavier than needed
Third-party app acting for your usersDoes not fit: no user consent, no per-user scopeFits: authorisation code with PKCE, scopes, revocable grants
Machine-to-machine within your organisationAcceptable short term with a secrets managerBetter: client credentials with private_key_jwt or mTLS, short-lived tokens. See the Machine-to-Machine OAuth Guide
Fine-grained, per-endpoint permissionsPossible only with bespoke key scopingNative through scopes and audiences
Fast revocation after compromiseRotate the key, which breaks every caller using itRevoke the grant or refresh token for one client or user

A related anti-pattern is wrapping an API key in a JWT: signing a long-lived key into a token with no exp gains nothing. Migration paths and hardened key patterns are in the API Keys vs OAuth Tokens Guide.

Worked scenario: reviewing "we use JWT"

A product team presents an API design: a mobile app posts a username and password to /login, receives a JWT signed with HS256 using a secret held in every microservice, and sends it on each request. The token has sub and role claims and an exp of 30 days. A partner now wants to read customer orders on behalf of users.

  1. Classify: this is JWT without OAuth. There is no client identity, no audience, no consent model, and a shared secret means any compromised service can mint admin tokens.
  2. Introduce an authorisation server: the app uses the authorisation code flow with PKCE (a native app pattern, see the OAuth Native Apps Guide); the partner registers as a separate client and gets user consent for an orders:read scope.
  3. Choose the access token format: internal APIs get RFC 9068 JWTs signed with an asymmetric key, 10-minute exp, aud per API; the partner-facing gateway introspects and forwards an internal token, so the partner never sees claims.
  4. Separate identity: the app reads the user's profile from the ID Token or UserInfo, not from the access token.
  5. Retire the old tokens: run both validators in parallel, stop issuing legacy tokens, then reject any token without typ at+jwt after the longest legacy exp has passed.

Long-lived login JWTs also widen the blast radius of unrelated leaks: in the Wyndham hardcoded app password breach, the exposed database held customer login tokens, and whether they could still be used depended on whether they had been invalidated.

Decision guidance

  • First-party web app, same domain: a server-side session cookie is often simplest. If you use OAuth, keep tokens in a backend for frontend rather than the browser. See the OAuth Browser-Based Apps and BFF Guide.
  • Mobile or single-page app calling your APIs: OAuth with PKCE and short-lived access tokens; format per the JWT vs opaque decision.
  • Third parties or AI agents acting for users: OAuth is required for consent, scoping and revocation; JWT alone cannot express any of these.
  • Service to service: OAuth client credentials with JWT client assertions or mTLS, or workload identity federation; avoid shared HMAC secrets.
  • Small organisations: use a managed identity provider and its default token format, a maintained validation library and short lifetimes. Do not write a JWT login service.
  • Large organisations: publish one token validation profile (algorithms, issuers, audiences, typ, lifetimes) and enforce it at gateways and in shared libraries; see API Gateway vs In-Service Token Validation.

How to implement

  1. Inventory token types: list every JWT and token your estate issues or accepts, with issuer, audience, typ, algorithm and lifetime. Flag self-issued session JWTs and any API that accepts ID Tokens.
  2. Write the validation profile: allowed algorithms, issuer per environment, audience per API, required typ at+jwt for access tokens, maximum lifetime and clock skew.
  3. Enforce in audit mode: log, but do not reject, tokens that fail the new checks for one to two weeks; review which clients send ID Tokens or tokens for the wrong audience.
  4. Fix clients, then enforce: move clients to proper access tokens and scopes, then switch the checks to reject with invalid_token.
  5. Replace bespoke login JWTs: migrate to an authorisation server and OIDC, or to server-side sessions for first-party web apps.
  6. Roll back safely: keep the enforcement switch per API and per check so one failing integration does not force removing all validation.

Detection and measurement

  • Log validation failures by reason: wrong typ, wrong aud, unknown kid, expired, bad signature, with client_id and a token hash, never the token. The OWASP Logging Cheat Sheet lists JWT validation problems among events to log.
  • Alert on: any token with alg none or an algorithm outside the allowlist; ID Tokens presented to APIs; tokens from unexpected issuers.
  • Metric: profile coverage: share of APIs enforcing aud and typ checks. Target 100% for externally reachable APIs.
  • Metric: maximum access token lifetime across issuers. Target minutes, not hours.
  • Metric: self-issued JWT schemes remaining: count, trending to zero.
  • Metric: long-lived API keys on endpoints that serve user data, trending to zero.

Framework mapping

FrameworkReferenceRelevance
NIST SP 800-53 Rev 5IA-5 Authenticator ManagementToken and key lifetimes, signing key protection, API key rotation
NIST SP 800-53 Rev 5IA-9 Service Identification and AuthenticationClient authentication with JWT assertions or mTLS
NIST SP 800-53 Rev 5AC-3 Access EnforcementScope and audience checks at the API
NIST SP 800-53 Rev 5SC-23 Session Authenticity; SC-8 Transmission Confidentiality and IntegrityToken integrity and TLS for bearer tokens
OWASP API Security Top 10 2023API2:2023 Broken AuthenticationUnsigned or unexpired JWTs, OAuth treated as authentication
MITRE ATT&CK v20T1528 Steal Application Access Token; T1550.001 Application Access Token; T1606 Forge Web CredentialsToken theft and replay; forged tokens when signing keys or validation fail

Common failure patterns

  • "We use JWT" as the security design: no issuer separation, audience or scope model, so any valid token works everywhere.
  • ID Tokens sent to APIs: a single-page app forwards the ID Token because it was easier to get, and the API accepts it because the signature is valid.
  • Shared HMAC secret across services: every verifier can mint tokens; one leaked configuration file means forged admin tokens.
  • Thirty-day login JWTs with no revocation: logout and password reset do nothing until exp.
  • Clients parsing access tokens: features break when the identity provider changes format, and claims leak to devices. RFC 9068 says the client must not inspect the access token.
  • API keys standing in for delegated access: a partner integration given a key with full account access instead of a user-consented, scoped OAuth grant.

Practitioner checklist

  • Describe every API's design as "OAuth flow plus token format", never "JWT".
  • Require typ at+jwt, exact iss and per-API aud for JWT access tokens.
  • Configure an explicit algorithm allowlist; reject alg none.
  • Resolve signing keys only from the configured issuer's JWKS.
  • Reject ID Tokens at every API.
  • Keep JWT access token lifetimes in minutes and use refresh token rotation.
  • Replace self-issued login JWTs with OIDC or server-side sessions.
  • Use RFC 7523 client assertions or mTLS instead of shared client secrets for machine clients.
  • Limit API keys to low-risk, server-side use with rotation and network restrictions.
  • Log validation failures by reason without logging tokens.

Standards and references

Related NHI Mgmt Group resources: JWT Security Guide · JWT vs Opaque Tokens · OAuth 2.0 and OpenID Connect Guide · API Keys vs OAuth Tokens Guide · API Security Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org