OAuth 2.0 and OpenID Connect have become the backbone of modern digital identity: from signing in with Google to one application accessing another's API, they define how to authorize and authenticate without exposing passwords. Implementing them poorly, however, opens gaps that range from session hijacking to corporate data leakage. This guide explains the concepts, the recommended flows and the defenses every engineering team should adopt.
OAuth 2.0 is not authentication: it is delegated authorization
The most common misconception about OAuth 2.0 (defined in RFC 6749) is treating it as a login protocol. It was not designed for that. OAuth 2.0 solves a different problem: how an application (the client) obtains limited access to a user's resources hosted on another service, without that user having to share their credentials with the application. In other words, OAuth is a framework for delegated authorization.
The classic example: a calendar app wants to read your events from Google Calendar. Instead of you handing your Google password to the app, Google issues a token that grants the app permission to read only the calendar, for a limited time, and that can be revoked at any moment. The password never leaves Google's domain.
When what you really need is to know who the user signing in is, plain OAuth 2.0 is insufficient and dangerous to improvise. That is what OpenID Connect exists for.
OpenID Connect: the authentication layer on top of OAuth
OpenID Connect (OIDC), specified in OpenID Connect Core 1.0, is a thin identity layer built on top of OAuth 2.0. It reuses the same flows but adds a decisive piece: the ID Token, a signed JWT that verifiably asserts who the authenticated user is, when it happened and through which provider.
The practical rule is straightforward: if you need to authorize access to resources, use OAuth 2.0; if you need to authenticate users (login, SSO), use OpenID Connect. Building a login system with OAuth 2.0 alone, inspecting access tokens to "figure out" the user, is one of the recurring causes of identity security failures. The access token is meant for an API, not for the client, and does not guarantee it was issued for the application reading it.
OIDC also standardizes pieces that identity providers used to implement in proprietary ways: the UserInfo endpoint, the discovery document (well-known configuration), the public verification keys (JWKS) and identity scopes like openid, profile and email. This standard is what makes federated login and SSO across different vendors interoperable and auditable, instead of a patchwork specific to each provider.
The four roles of the protocol
Understanding OAuth starts with understanding who does what. The framework defines four roles:
- Resource Owner: usually the end user, who holds the data and grants authorization.
- Client: the application that wants to access the resources on the user's behalf. It can be confidential (a backend able to keep secrets) or public (a SPA or mobile app, which cannot protect a secret).
- Authorization Server: authenticates the user, obtains their consent and issues the tokens. It is the heart of the system's trust.
- Resource Server: the API that hosts the protected data and validates the received access tokens before responding.
Grant types: choose the right flow
OAuth 2.0 defines several grant types (authorization flows). The wrong choice is a direct source of vulnerabilities. The table below summarizes the relevant flows, their recommended use and their status according to the OAuth 2.0 Security Best Current Practice (RFC 9700) and OAuth 2.1.
| Grant type | Typical use | Status |
|---|---|---|
| Authorization Code + PKCE | Web apps, SPAs, mobile apps and any client with a user present | Recommended (standard) |
| Client Credentials | Machine-to-machine communication, with no user (backend to API) | Recommended |
| Device Authorization (Device Code) | Devices without a browser or keyboard (TVs, IoT, CLIs) | Recommended |
| Refresh Token | Renewing access tokens without re-authenticating the user | Recommended (with rotation) |
| Implicit | Formerly used by SPAs | Deprecated |
| Resource Owner Password Credentials | Direct exchange of username and password for a token | Deprecated |
Authorization Code with PKCE: today's standard
The Authorization Code flow is the most secure for any client involving a human user. The browser is redirected to the authorization server, the user authenticates and consents, and the server returns a short-lived code. The client exchanges that code for tokens in a server-to-server call, out of the browser's reach.
PKCE (Proof Key for Code Exchange, RFC 7636) reinforces this flow against code interception. The client generates a random secret (code_verifier), sends its hash (code_challenge) at the start of the flow and presents the original verifier when exchanging the code. Even if an attacker intercepts the code, they cannot exchange it without the verifier. OAuth 2.1 makes PKCE mandatory for all clients, including confidential ones.
Client Credentials: machine to machine
When no user is involved (one service calling another), the Client Credentials flow lets the confidential client itself obtain a token using its own credentials. It is the correct flow for backend integrations, scheduled jobs and microservices. Since there is no user, there is no refresh token or ID token: the client simply re-authenticates when the token expires.
Device Authorization Grant: screens without a keyboard
For devices with limited input — a smart TV, an IoT device, a command-line tool — the Device Authorization Grant displays a short code that the user types on another device (phone or computer) to authorize. The device polls the authorization server until it receives the tokens, without ever handling the user's password.
Why Implicit and Password are deprecated
Two historical flows have been banned by current best practices:
- Implicit Grant: delivered the access token directly in the redirect URL (in the fragment). This exposes the token to browser history, logs, Referer headers and third-party scripts, and offers no protection against interception. It was replaced by Authorization Code + PKCE, which also works perfectly in SPAs.
- Resource Owner Password Credentials (ROPC): the application directly collects username and password and exchanges them for a token. This reintroduces exactly the problem OAuth came to solve — the client now sees the password — while also making MFA, SSO and external identity providers unworkable.
RFC 9700explicitly recommends against using it.
OAuth 2.1 consolidates these decisions: it removes Implicit and ROPC, requires PKCE and prohibits delivering tokens in the URL.
The three tokens and their roles
Confusing tokens is another classic source of error. There are three distinct artifacts, with different recipients and lifetimes:
- Access Token: a short-lived credential presented to the Resource Server to access the API. It must be treated as opaque by the client — the API is what interprets it. Short-lived, from minutes to a few hours.
- Refresh Token: a longer-lived credential used to obtain new access tokens without re-authenticating the user. Being sensitive, it requires secure storage and, ideally, rotation on each use.
- ID Token: exclusive to OpenID Connect. It is a signed
JWTintended for the client, containing claims about the user (identifier, issuer, audience, authentication time). It should never be sent to an API as if it were an access token.
The most common risks and attacks
OWASP and RFC 9700 catalog the vectors that most often take down OAuth implementations:
- Token theft: tokens in logs, in insecure browser storage or traveling without TLS can be captured and reused. Tokens are credentials — treat them like passwords.
- CSRF in the authorization flow: without the
stateparameter, an attacker can force the victim to complete a flow they control. Thestatemust be random, tied to the session and validated on return. - Open redirect / open redirect_uri: if the server accepts any
redirect_urior does partial matching, the code or token can be diverted to an attacker's domain. Validation must be by exact match. - Code interception: on mobile apps, another malicious app can capture the code in the redirect. PKCE neutralizes this attack by requiring the verifier at exchange.
- Token leakage: leaks via the Referer header, authorization-server mix-up or tokens in URLs. Mitigated by never using fragment-based flows and by binding tokens to the client.
- Scope creep: requesting more permissions than necessary widens the damage of a compromised token. The principle of least privilege applies to scopes too.
Secure implementation best practices
Bringing together the recommendations of RFC 9700, OAuth 2.1 and OWASP, the essential defenses are:
- PKCE always: use Authorization Code + PKCE on all clients, public and confidential.
- Validate the redirect_uri by exact match: register full URIs and reject any divergence. Never accept arbitrary wildcards.
- Use and validate the
stateparameter: it protects against CSRF and helps rebind the flow to the user's session. - Short tokens with refresh rotation: short-lived access tokens and refresh tokens with rotation (revoking the previous token on each use) limit the abuse window and detect reuse.
- Minimal audience and scope: issue tokens with the correct
audienceand only the necessary scopes; validate audience and scope at the Resource Server. - Secure token storage: avoid exposing tokens to third-party JavaScript; prefer
HttpOnlyandSecurecookies with a backend mediator (BFF pattern) where applicable. - Token binding to the client (mTLS / DPoP): tokens bound via mTLS or DPoP (Demonstrating Proof of Possession) stop being pure bearer tokens — a stolen token is useless without the legitimate client's key.
- TLS everywhere: no authorization, token or resource endpoint should operate without TLS.
OAuth 2.1: the consolidation
OAuth 2.1 is not a new protocol, but the unification of the best practices accumulated since 2012 into a coherent document. Its central decisions: mandatory PKCE, removal of Implicit and ROPC, prohibition of tokens in URLs, requirement of exact redirect_uri matching and clear guidance on refresh token rotation. For teams starting today, designing directly to OAuth 2.1 is the lowest-risk path and the one that ages best.
How Decripte helps
At Decripte, we treat identity as a critical security surface. Our work in AppSec and identity management covers everything from reviewing authentication and authorization architecture — flow selection, token validation, OIDC provider configuration — to offensive testing against OAuth implementations looking for open redirects, PKCE flaws and token leakage. We serve everyone from micro-business to enterprise, from 1 to more than 100,000 employees, with the same technical rigor.
If you are designing or auditing login and API integrations, start with our diagnostic: start for free and explore the plans to protect your platform end to end.
References
- RFC 6749 - The OAuth 2.0 Authorization Framework
- RFC 7636 - Proof Key for Code Exchange (PKCE)
- RFC 9700 - Best Current Practice for OAuth 2.0 Security
- OpenID Connect Core 1.0
- OWASP - OAuth 2.0 and API Security Cheat Sheets / Top 10
- OAuth 2.1 Authorization Framework (draft)
