OAuth oauth.net

Frequently Asked Questions about OAuth

Concepts

Is OAuth for authentication or authorization?

OAuth is an authorization protocol — it grants an application access to resources on a user's behalf. It says nothing about who the user is. Using OAuth alone as a login mechanism is a common mistake that creates security vulnerabilities. If you need to know who the user is, use OpenID Connect, which is a thin identity layer built on top of OAuth 2.0.

Read more: OAuth 2.0 is not an authentication protocol →

What is the difference between OAuth 2.0 and OpenID Connect?

OAuth 2.0 handles authorization — granting scoped access to APIs and resources. OpenID Connect (OIDC) is built on top of OAuth 2.0 and adds user authentication: it defines how an application can find out who the user is and returns a signed ID Token alongside the access token. When you "Sign in with Google," that is OpenID Connect, not raw OAuth.

Read more: ID Tokens vs Access Tokens →

What is OAuth 2.1?

OAuth 2.1 is a consolidation of OAuth 2.0 and its security best practice extensions into a single document. It removes deprecated flows (Implicit, Password grant), mandates PKCE for all Authorization Code flows, and tightens redirect URI matching rules. Implementations compliant with OAuth 2.0 and modern security best practices will likely require only minor changes to meet OAuth 2.1.

Read more: OAuth 2.1 →

What is the difference between OAuth 1.0 and OAuth 2.0?

OAuth 2.0 is not backward-compatible with OAuth 1.0. OAuth 1.0 required cryptographic signing of every request using a shared secret; OAuth 2.0 relies on TLS for transport security and uses bearer tokens, making it simpler to implement. OAuth 1.0 is considered legacy — new implementations should use OAuth 2.0.

Read more: OAuth 1.0 →

Choosing the Right Approach

How do I choose which grant type to use?

For apps that act on behalf of a user — whether a server-side web app, single-page app, or mobile app — use the Authorization Code flow with PKCE. For server-to-server communication where there is no user involved, use the Client Credentials grant. If you're building for a device without a browser, such as a TV or CLI tool, use the Device Authorization flow. The Implicit flow and the Password grant have been deprecated and should not be used in new applications.

Read more: OAuth Grant Types →

Do I need OAuth if I own both the client and the API?

If you control both the client and the API and there is only ever one client, you may not need OAuth at all — a simpler API key approach can work fine, although comes with the downsides and security risks of shared secrets and static configuration. OAuth becomes valuable when you need to support delegated access, when multiple clients need to talk to the same API, or when third-party developers need to build on top of your platform. For a simple architecture like a client talking to a single API, you can also use the "Private Key JWT" client authentication mechanism defined in OAuth to avoid shared secrets.

Read more: Private Key JWT →

Why is the Password grant deprecated?

The Password grant (Resource Owner Password Credentials) requires users to give their credentials directly to the client application, risking the client leaking or misusing the password. This prevents using phishing-resistant flows, breaks multi-factor authentication, and means the client handles credentials it should never see. Authorization Code + PKCE is the correct replacement, even for first-party login UIs.

Read more: Password Grant →PKCE →

Security and Token Handling

Can I use a client secret in a mobile or single-page app?

No. Mobile apps and SPAs are typically public clients. A mobile app in an app store or a SPA on a static website can't be deployed with credentials. A client secret embedded in an app binary or JavaScript bundle is not a secret. Public clients like these still use the Authorization Code flow with PKCE, they just omit client authentication.

Read more: Client Types →PKCE →

Where should I store tokens in a browser-based app?

Avoid storing tokens in localStorage or sessionStorage, since any JavaScript running on the page — including third-party scripts — can read them. The safest option for browser-based apps is to keep tokens in memory only, or to use a backend-for-frontend (BFF) pattern where the server holds the token and communicates with the browser via HttpOnly cookies that JavaScript cannot access.

Read more: Browser-Based Apps →

Should access tokens be JWTs or opaque strings?

JWTs allow the resource server to validate a token locally without making a network request, which is useful at scale. The tradeoff is that a JWT cannot truly be revoked before it expires without adding back state management. Once issued, it remains valid until the expiration time passes. Opaque tokens require calling the token introspection endpoint on each request, but they can be revoked instantly. Which you choose depends on whether you prioritize performance or the ability to immediately invalidate tokens.

JWT Access Tokens →Token Introspection →Token Revocation →

What is the state parameter and is it required?

The state parameter is a random, unguessable value that the client generates before sending the user to the authorization server, and then verifies when the user returns. Its primary purpose is CSRF protection. PKCE also provides CSRF protection, and can be used instead of the state parameter for this purpose.

Read more: PKCE →

Implementation

Why does OAuth use expires_in instead of expires_at?

Client clocks are often wrong, so a relative offset in seconds is more reliable than an absolute timestamp that depends on accurate local time. Clients should record the current time when they receive a token and compute the expiry from expires_in rather than relying on the server's clock. You can read the previous discussion about this in the mailing list archives.

Why does the redirect URI need to match exactly?

The redirect URI must match exactly because it is one of the primary security controls in the authorization code flow. If an attacker can register a URI that is similar to yours — a different subdomain, an added path segment, or a URL parameter — they can intercept the authorization code and exchange it for a token themselves. Wildcards and partial matching make this trivial to exploit, which is why OAuth 2.1 requires exact string matching with only an exception for localhost redirect URIs for native apps.

Read more: Security Best Current Practice →