Authentication choices matter in Application Programming Interface (API)-driven architectures. As your applications scale across cloud platforms and microservices architectures, choosing the right Representational State Transfer (REST) model, including the right REST authentication approach, becomes a core concern. JSON Web Tokens (JWTs) and OAuth address that concern.
JWT is a token format used to securely transmit data. OAuth is an authorization framework designed to delegate access. Treating them as interchangeable leads to misconfigurations and security vulnerabilities. It can also make auth systems too complex.
Separating token format from authorization and identity keeps decisions aligned with your app's authentication setup.
In brief
- JWT is a token format, while OAuth is an authorization framework.
- OIDC connects OAuth authentication with JWT-based ID tokens.
- OAuth 2.1 removes older insecure flows and makes Proof Key for Code Exchange (PKCE) the default baseline.
- A common production pattern uses OAuth for delegation and JWT as the token format.
JWT vs OAuth: Understanding self-contained tokens and authorization frameworks
JWTs and OAuth solve different problems. JWT is a compact token format used for securely passing information, while OAuth is a full authorization framework for granting scoped access to resources. Choosing between them, or combining both, depends on your authentication and authorization needs.
JWT: Self-contained authentication tokens
A JSON Web Token (JWT) is a stateless, compact token format defined in the Request for Comments specification RFC 7519. It lets users authenticate and carry necessary claims without relying on server-side sessions.
A JWT consists of three Base64URL-encoded parts concatenated with periods (header.payload.signature):
- Header: Contains metadata about the token type and the signing algorithm (e.g., RS256 or ES256).
- Payload: Contains claims about the entity (typically the user) and additional data: user ID, roles, custom permissions, and token expiration time.
- Signature: Created by combining the encoded header, encoded payload, and a secret key using the algorithm specified in the header. This ensures the token hasn't been tampered with.
The server validates your credentials, creates a JWT authentication token, and hands it back. On subsequent requests, you attach the JWT in the Authorization header. The server verifies the signature and processes your request based on the token's contents, with no server-side session required.
This stateless nature makes JWTs a good fit for distributed systems and microservices. Since all necessary information lives inside the token itself, any service with the right key can validate it independently.
OAuth: Framework for delegated authorization
OAuth is an authorization framework, defined in RFC 6749, designed to delegate access to resources without exposing user credentials. It allows secure, limited access across applications, which is how API authorization works in most modern systems.
OAuth defines four essential roles:
- Resource Owner: The user who grants permission for access.
- Client: The application requesting access on behalf of the Resource Owner.
- Authorization Server: Issues tokens after authenticating the Resource Owner and obtaining authorization.
- Resource Server: Hosts the protected resources and validates tokens before serving data.
OAuth provides several grant types for different scenarios. The Authorization Code flow with PKCE is the recommended default for browser-based and mobile apps. It involves a front-channel authorization request and a back-channel token exchange, with PKCE protecting against code interception attacks. For server-to-server services communicating without user involvement, the Client Credentials flow is the right choice.
Older flows like the Implicit grant and Resource Owner Password Credentials (ROPC) are deprecated under OAuth security guidance and removed entirely from the OAuth 2.1 specification.
OAuth is the framework behind scenarios where users grant third-party apps limited access to their accounts without sharing credentials, like when you use "Login with Google" on other websites. That same delegation model powers social login: users sign in with existing accounts instead of creating new credentials.
Where OpenID Connect (OIDC) fits in
OAuth is fundamentally an authorization protocol: it defines what a user can access. As the OpenID Connect Core specification notes, without profiling OAuth 2.0, it is "incapable of providing information about the authentication of an End-User."
OpenID Connect (OIDC) fixes this by adding an identity layer on top of OAuth 2.0. When a client includes the openid scope in an authorization request, the authorization server, now called the OpenID Provider, returns an ID Token alongside the standard access token. Per the OIDC Core 1.0 specification, this ID Token is a JWT containing standardized claims like iss (issuer), sub (subject identifier), aud (audience), and exp (expiration).
OIDC links JWT and OAuth formally. OIDC connects them by profiling OAuth 2.0 for authentication and requiring JWT as the format for identity assertions. Both Google and Microsoft implement OIDC this way, issuing signed JWT ID tokens through their OAuth flows.
If you're comparing "JWT vs OAuth vs OIDC," read the stack as a dependency chain. RFC 6749 (OAuth 2.0) provides the authorization framework that OIDC Core 1.0 profiles for authentication. RFC 7519 (JWT) provides the token format that OIDC requires.
Reading the stack this way keeps identity and delegation concerns separate from token format.
Architectural differences: Token format vs authorization protocol
JWT defines how tokens are structured, encoded, and validated. It's about the format of information exchange. OAuth outlines how different parties interact to support secure access delegation. It's about the process. They serve different purposes and often work together in a well-planned API design.
These architectural differences show up in two practical areas:
- Implementation complexity: JWT implementation tends to be straightforward; tokens are self-contained and verified locally without database lookups, which suits microservices well. OAuth requires more setup: authorization servers, resource servers, client configuration, and grant type selection. The tradeoff is that OAuth gives you token revocation and scope-based access control that JWT alone doesn't offer.
- Runtime performance: JWT's stateless verification skips database queries entirely, which helps in microservices where inter-service communication is already a cost. OAuth's framework may introduce additional network calls between services, though this overhead buys you centralized token lifecycle management.
The two often work better together than as an either-or decision.
Security considerations: Vulnerabilities and protections
JWT and OAuth each come with distinct security tradeoffs. Your choice, and how you implement it, should match your project's risk profile and token lifecycle needs within your infrastructure. For broader context, see these API security best practices.
JWT security risks and mitigations
Key JWT risks to account for:
- Algorithm confusion: The most critical JWT vulnerability is manipulation of the
algheader. An attacker can change it tonone(or case variants likenoNe) to bypass signature verification entirely. Per RFC 8725, it's safer to configure explicit allowlists of accepted algorithms rather than blocklists, and to stay with strong options like ES256 or RS256. The update to that Best Current Practice (BCP), rfc8725bis, has reached draft-07 and is awaiting IESG action; it reinforces the allowlist rule and documents the case-sensitivity attack, where "an attacker could change the 'alg' value to 'noNE' and bypass the security check." - Token revocation: JWTs have no built-in revocation mechanism. A compromised token remains valid until it expires. A leaked long-lived token is painful: without extra controls, you wait out the expiry window. A safer pattern is short-lived tokens paired with refresh tokens, plus a token denylist keyed on the
jticlaim for high-security systems, per the Open Worldwide Application Security Project (OWASP) JWT Cheat Sheet. - Payload exposure: JWT payloads are Base64URL-encoded, not encrypted. Anyone with the token can read its contents. Keep sensitive data out of JWT payloads, especially credentials and payment data. For sensitive data, JSON Web Encryption (JWE) tokens are the safer option.
- Cross-Site Scripting (XSS) token theft: Tokens stored in
localStorageorsessionStorageare accessible to any JavaScript running in the origin, so a single XSS flaw discloses every token. The OWASP Session Management Cheat Sheet is blunt: "Do not store authentication tokens, session IDs, JWTs, refresh tokens, or any credential inlocalStorageorsessionStorage." HttpOnly cookies and a strict Content Security Policy are safer defaults.
Handled together, these mitigations make JWTs safer without giving up their stateless advantages.
OAuth security risks and mitigations
Key OAuth risks to account for:
- Redirect URI manipulation: Attackers can manipulate redirect URIs to steal authorization codes or tokens. It helps to validate redirect URIs using exact string matching, with no wildcards or prefix matching. RFC 9700 (OAuth 2.0 Security Best Current Practice), published as BCP 240, makes this normative: authorization servers must use exact string matching when comparing redirection URIs against pre-registered ones.
- Cross-site request forgery (CSRF) via state parameter: Skipping or poorly implementing the
stateparameter exposes you to cross-site request forgery attacks. A random state value should be generated, stored, and verified in every OAuth transaction. - Token interception: Without encryption, tokens can be intercepted in transit. HTTPS should protect all OAuth communications and token exchanges.
OAuth 2.1 changes directly address many of these risks by mandating PKCE and requiring exact redirect URI matching. It also prohibits bearer tokens in query strings. If you're setting up OAuth today, following the 2.1 draft gives you a stronger security baseline by default. The same principles apply to protecting a Content Management System (CMS), including a headless CMS deployment.
Shared best practices
Regardless of which approach you use, a solid baseline applies every time:
- HTTPS everywhere, with HttpOnly + Secure cookies for token storage instead of localStorage.
- Token validation on every request, including signatures, expiration
exp, issueriss, and audienceaud.
National Institute of Standards and Technology (NIST) SP 800-228 (Guidelines for API Protection for Cloud-Native Systems), now final in its upd1 edition, makes expiry checking part of validation itself: "Verify signatures, and check for expiry during token validation. For example, when processing JWTs, the 'exp' claim RFC 7519 must be checked." It also rules out weak signing outright, prohibiting JWTs with "alg: none," weak algorithms, or short key lengths. These fundamentals apply whether you're using JWT, OAuth, or both.
OAuth 2.1: What changes for JWT and OAuth implementations
If you're implementing OAuth today, you're effectively implementing OAuth 2.1. The specification remains an Internet-Draft, draft-15, with IESG submission targeted for December 2026, and consolidates OAuth 2.0 with the security practices from RFC 9700 and related BCPs. OAuth 2.1 changes several implementation defaults:
- PKCE requirement: Previously optional and recommended only for public clients, PKCE is now the baseline for the authorization code flow. Per draft-15, "An authorization server MUST reject requests without a
code_challengefrom public clients, and MUST reject such requests from other clients unless there is reasonable assurance that the client mitigates authorization code injection in other ways." TheS256challenge method is the safer default. - Implicit Flow removed: SPAs should now use the Authorization Code flow with PKCE per the Browser-Based Apps BCP, which has been approved as a BCP and sits in the RFC Editor queue.
- ROPC removed: The IETF is developing a first-party apps spec, draft-04, that defines an Authorization Challenge Endpoint for native apps that previously relied on ROPC.
- Redirect URI matching: Each distinct redirect URI requires separate registration, and authorization servers must reject mismatches.
- Query-string bearer ban: Sending tokens as query-string parameters exposes them in browser history and server logs; Referer headers can leak them too. The draft specifies only the
Authorizationheader and form-encoded body methods. - Refresh token protection: Per draft-15: "For public clients, the authorization server MUST either use sender-constrained refresh tokens or refresh token rotation." With rotation, the server issues a new refresh token on each exchange and invalidates the previous one.
These changes make Authorization Code with PKCE the practical baseline for new OAuth implementations.
Decision framework: Choosing between JWT, OAuth, or both
Deciding when to use JWT vs OAuth depends on your application's specific needs.
JWT vs OAuth comparison table
| Feature | JWT (JSON Web Token) | OAuth (Open Authorization) |
|---|---|---|
| Type/Nature | Token format for identity and claims | Authorization framework for delegated access |
| Statefulness | Stateless; no server-side session required | Typically stateful; auth server manages token lifecycle |
| Primary Use Case | API authentication, microservices, service-to-service | Third-party app access, social logins, permission delegation |
| Token Validation | Local signature verification with shared or public key | Server-side introspection or local verification (when using JWT tokens) |
| Revocation Support | Requires custom handling, such as denylists and short expiry | Built-in token revocation and lifecycle management |
| OIDC Role | Mandatory format for ID tokens | Underlying authorization framework that OIDC profiles |
| Token Size | Grows with claims count | Opaque tokens are small; JWT-formatted tokens follow JWT sizing |
| OAuth 2.1 Alignment | Unchanged as a format; used within OAuth 2.1 flows | Consolidates security BCPs; mandates PKCE, removes Implicit/ROPC |
| Best For | Stateless auth in distributed systems, cross-platform portability | Delegated authorization, fine-grained scopes, third-party integrations |
When to choose JWT
JWT is the right call when you need stateless authentication without centralized session storage, particularly in distributed systems where a database lookup per request would create bottlenecks. It works well in cross-platform environments where services use different languages but need to share user information via a standardized format.
JWT is especially useful when you need:
- Performance-critical APIs
- Service-to-service communication in microservices
- Resource-constrained environments like IoT
These cases benefit from JWT's lightweight, locally verifiable nature.
When to choose OAuth
OAuth makes more sense when you need:
- Third-party integrations: External apps access user resources with proper consent, like "Sign in with Google" or GitHub social login.
- Complex authorization: Multiple permission levels need to be enforced consistently.
- Delegated access: Apps need limited access to user accounts without receiving credentials.
- Fine-grained scope control: Different clients require different access levels.
Those scope decisions can get messy as integrations grow, so having a framework helps. If you need immediate token revocation capabilities, OAuth's built-in lifecycle management handles this natively.
When to use both (the hybrid approach)
A common production pattern combines both technologies. OAuth manages the authorization flow, scoped permissions, consent, and token lifecycle. JWT is the access token format within that flow, so resource servers validate tokens locally without calling back to the authorization server on every request. RFC 9068 standardizes exactly this pattern. It profiles JWT as an interoperable format for OAuth 2.0 access tokens.
Major platforms use this pattern: Google uses OAuth 2.0 for authorization while issuing JWTs as ID tokens that APIs verify locally. Platforms like Strapi 5 take a similar approach. Strapi supports local auth and JWT tokens, along with third-party OAuth providers such as Auth0 provider setup and a built-in Role-Based Access Control system for managing permissions. The combination pairs OAuth's delegation model with JWT's stateless efficiency.
Implementation best practices
Implementation details are where JWT and OAuth choices become security decisions. Start with token storage and lifecycle management, then select the right grant types so the system stays durable in production.
Token storage and transmission
Where you store tokens directly impacts your security posture. For web applications, HttpOnly cookies with the Secure and SameSite attributes are the strongest default. They block JavaScript access, preventing XSS-based theft, and restrict cross-origin sending. For mobile apps, platform-specific secure storage is the safer default.
For transmission, the Authorization: Bearer header is the standard approach when making authenticated API requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...This keeps tokens out of URLs and records such as browser history and server logs, and aligns with OAuth 2.1's removal of bearer tokens from query strings.
Token lifecycle management
Short-lived access tokens paired with refresh token rotation is the pattern that balances security with usability. Short-lived access tokens with an exp claim reduce the blast radius if a token leaks. A longer-lived refresh token can sit alongside the JWT, be stored securely, and rotate on each exchange. The server issues a new refresh token and invalidates the old one.
async function refreshAccessToken() {
const response = await fetch('/api/refresh', {
method: 'POST',
credentials: 'include'
});
if (response.ok) {
const { accessToken } = await response.json();
return accessToken;
} else {
window.location.href = '/login';
}
}In Strapi 5, the Users & Permissions refresh mode uses 10-minute access tokens with refresh tokens capped at 30 days. This matches RFC 9700's short-lived token guidance out of the box.
This refresh exchange is also your re-evaluation checkpoint. The authorization server can check whether the user is still authorized before issuing a new token, which aligns with Zero Trust principles.
Choosing the right OAuth grant type
Two flows cover most cases.
Authorization Code + PKCE is the default for browser-based and mobile apps. The flow starts with generating a code_verifier, deriving a code_challenge using SHA-256, sending the challenge in the authorization request, and sending the verifier in the token exchange. This is mandatory under OAuth 2.1 for all client types.
Client Credentials is the right choice for server-to-server authentication where no user context exists: background jobs and automated microservice-to-microservice calls.
Planning your authentication strategy for change
Authentication keeps changing. Several concrete shifts are reshaping how you protect APIs and users:
- Zero Trust operations: For JWT and OAuth implementations, this means shorter token lifetimes and refresh-based re-evaluation. Each request should use the narrowest practical scope.
- Passkeys replacing passwords: Built on FIDO2/WebAuthn, passkeys use public-key cryptography to eliminate phishable credentials entirely. Microsoft made new accounts passwordless by default on May 1, 2025. Passkeys replace the authentication factor inside your OAuth flow; the token and delegation layer remains unchanged.
- Demonstrating Proof of Possession (DPoP) adoption: RFC 9449 defines a mechanism to cryptographically bind tokens to the client that obtained them. A stolen token becomes unusable without the client's private key. The FAPI 2.0 Security Profile, final since February 2025, mandates sender-constrained access tokens via DPoP or mutual Transport Layer Security (mTLS).
- Artificial Intelligence (AI) agent auth: The Model Context Protocol (MCP) spec states that "Authorization servers MUST implement OAuth 2.1" and requires clients to implement PKCE with the
S256method. OAuth 2.1's security model is the baseline for new protocol design, and it applies directly to CMS tooling: the Strapi MCP server connects AI agents to your content through the same authorization layer.
To keep room for change, put authentication behind modular services and keep supported auth methods and grant types current.
Wrapping up: Format plus framework
The JWT vs OAuth question resolves once you separate token format from authorization flow. OIDC adds the authentication layer on top of OAuth. For a common production setup, OAuth handles scoped delegation and token lifecycle, while JWT gives resource servers locally verifiable tokens.
If you use Strapi 5, you get JWT-based local authentication, refresh token support, third-party OAuth providers, and Role-Based Access Control as built-in options, which gives you a starting point for this kind of setup.





