OAuth 2.0 and OpenID Connect sit underneath almost every modern sign-in, API call, SaaS integration and AI agent connection. OAuth lets an application get limited access to a resource on someone's behalf without handling their password. OpenID Connect (OIDC) adds a standard way to learn who signed in. Identity teams meet both constantly, in single sign-on, in third-party app consent, in service-to-service tokens and in MCP servers, but the details that decide whether a deployment is secure are easy to get wrong. This guide explains the roles, flows, tokens and client types, what OAuth 2.1 changes, and the mistakes behind most OAuth incidents.
Key takeaways
- OAuth is for authorisation, OIDC is for authentication. An access token says what a client may do; an ID token says who the user is.
- Use the authorisation code flow with PKCE for applications acting for users, and client credentials (preferably with a key, not a secret) for services.
- The implicit and resource owner password flows are deprecated. OAuth 2.1 removes them.
- Most real-world OAuth damage comes from over-broad scopes, long-lived refresh tokens and stolen integration tokens, not from the protocol itself.
- Validate every token properly: issuer, audience, signature, expiry and, for ID tokens, nonce.
The roles
| Role | What it is | Example |
|---|---|---|
| Resource owner | The person or organisation who owns the data or can grant access | An employee |
| Client | The application requesting access | A calendar app, a CI pipeline, an AI agent |
| Authorisation server | Authenticates the user, gets consent and issues tokens | The organisation's identity provider |
| Resource server | The API that accepts access tokens | A mail API, a CRM API, an MCP server |
Grant types and when to use them
| Grant | Use it for | Notes |
|---|---|---|
| Authorisation code with PKCE | Web, mobile, desktop and single-page apps acting for a user | The default choice. PKCE (RFC 7636) stops intercepted codes being redeemed by someone else. |
| Client credentials | A service acting as itself, with no user | Authenticate the client with a private key JWT or mTLS rather than a shared secret where possible. |
| Device authorisation | Devices without a browser or keyboard, such as TVs and CLIs | RFC 8628. A known target for phishing with device codes; restrict where it is allowed. |
| Refresh token | Getting new access tokens without re-prompting the user | Rotate refresh tokens for public clients and bind or restrict them where possible. |
| Token exchange | Swapping one token for another with a different audience or scope | RFC 8693. Used for delegation across services and by AI agents acting on behalf of users. |
| Implicit (deprecated) | Nothing new | Returned tokens in the browser URL. Removed in OAuth 2.1. |
| Resource owner password (deprecated) | Nothing new | The client handles the user's password, defeating the point of OAuth. Removed in OAuth 2.1. |
Tokens
- Access token: presented to an API. It may be a signed JWT (RFC 9068 defines a JWT profile) or an opaque reference the API checks by introspection. It should be short-lived and limited to a specific audience and scope.
- Refresh token: used to get new access tokens. It is long-lived and powerful, so it needs strong protection, rotation and revocation.
- ID token (OIDC): a signed JWT telling the client who authenticated, when and how. It is meant for the client, not for calling APIs.
The Token and Session Security Guide covers lifetimes, validation, theft and binding in detail.
Client types
- Confidential clients run on a server and can hold a credential. Prefer asymmetric client authentication (private key JWT or mTLS) to shared client secrets, which leak like any other secret.
- Public clients, such as mobile and single-page apps, cannot keep a secret. They rely on PKCE and exact redirect URI matching.
- Dynamic registration: some ecosystems, including MCP, allow clients to register themselves. That makes client identity weaker, so policy and consent matter more. See the MCP Security Guide.
OpenID Connect in brief
OIDC builds on the authorisation code flow. The client requests the openid scope and receives an ID token alongside the access token. The ID token carries the issuer, subject (a stable user identifier), audience (the client), issue and expiry times, and a nonce the client sent to prevent replay. OIDC Discovery lets clients fetch the provider's endpoints and signing keys from a well-known document, and the UserInfo endpoint returns additional profile claims. For workforce single sign-on, OIDC and SAML do the same job; OIDC is simpler for modern and mobile applications.
What OAuth 2.1 changes
OAuth 2.1 is an IETF draft that consolidates OAuth 2.0 with the security lessons learned since 2012. At the time of writing it is still an Internet-Draft, with the working group aiming to send it for approval by the end of 2026. Its main changes are:
- PKCE required for the authorisation code flow.
- Implicit and resource owner password grants removed.
- Exact string matching of redirect URIs.
- Bearer tokens not allowed in URL query strings.
- Refresh tokens for public clients must be sender-constrained or one-time use.
The OAuth 2.0 Security Best Current Practice, published as RFC 9700 in January 2025, sets out the same recommendations for current OAuth 2.0 deployments.
Common OAuth mistakes and attacks
- Over-broad scopes: integrations that request full mailbox or full CRM access when they need a fraction. The Midnight Blizzard breach abused an OAuth application with full access to Exchange Online mailboxes.
- Stolen integration tokens: refresh tokens held by a SaaS vendor used to pull customer data. See the Salesloft Drift and Klue breaches.
- Consent phishing: a malicious app tricks a user into granting it access. The Cyberhaven extension breach started this way, and the ShinyHunters campaign talked staff into authorising malicious connected apps.
- Loose redirect URI matching: wildcard or prefix matching lets attackers steer codes to their own endpoints.
- Weak token validation: accepting tokens meant for another audience, not checking signatures, or trusting the algorithm named in the token.
- Token passthrough: a service forwards the token it received to another API instead of getting its own, breaking audience restriction and attribution.
- Client secrets in code: confidential client secrets committed to repositories or embedded in mobile apps.
The SaaS-to-SaaS and OAuth App Governance Guide covers how to govern third-party OAuth apps once they are connected.
OAuth for non-human identities and AI agents
- Services should use the client credentials grant with asymmetric client authentication, or workload identity federation, which exchanges a platform token for an access token without any stored secret. See the NHI Authentication Guide.
- Agents acting for users should use delegated tokens with narrow scopes and short lifetimes, and token exchange for each hop so every service sees both the user and the agent. See the AI Agent Authorisation Guide and the Multi-Agent and A2A Security Guide.
- For high-impact actions, Client-Initiated Backchannel Authentication (CIBA) lets a service ask the user to approve on their own device.
Practitioner checklist
- Use authorisation code with PKCE for every user-facing client, and remove implicit and password grants.
- Register exact redirect URIs and reject anything else.
- Authenticate confidential clients with private key JWT or mTLS rather than shared secrets.
- Keep access tokens short-lived and audience-restricted; rotate, bind or restrict refresh tokens.
- Validate issuer, audience, signature, expiry and nonce on every token, with a fixed list of allowed algorithms.
- Limit who can consent to which scopes, and review high-privilege OAuth apps regularly.
- Never pass a received token through to another service; use token exchange instead.
- Follow RFC 9700 now, and track OAuth 2.1 as it progresses.
Standards and references
- RFC 6749: The OAuth 2.0 Authorization Framework
- RFC 9700: OAuth 2.0 Security Best Current Practice (2025)
- The OAuth 2.1 Authorization Framework (IETF draft)
- RFC 7636: Proof Key for Code Exchange (PKCE)
- RFC 8693: OAuth 2.0 Token Exchange
- RFC 9068: JWT Profile for OAuth 2.0 Access Tokens
- OpenID Connect Core 1.0
Related NHI Mgmt Group resources: Token and Session Security Guide · SaaS and OAuth App Governance Guide · Identity Provider and SSO Security Guide · NHI Authentication Guide