Skip to main content

Skillber v1.0 is here!

Learn more

OAuth 2.0 & OpenID Connect

Checking access...

OAuth 2.0 is the industry-standard protocol for delegated authorization. It enables applications to obtain limited access to user accounts on HTTP services without exposing user credentials. OpenID Connect (OIDC) builds on OAuth 2.0 to add an identity layer, making it the dominant protocol for modern authentication and authorization.

Together, they power the authentication and authorization flows behind nearly every major SaaS platform, mobile app, and API ecosystem.

OAuth 2.0 — The Authorization Framework

OAuth 2.0 is not an authentication protocol — it is a delegated authorization framework. It allows a user (resource owner) to grant a third-party application (client) limited access to their resources (hosted by the resource server) without sharing their password.

OAuth 2.0 Roles

RoleDescriptionExample
Resource OwnerThe user who owns the protected dataEnd user
ClientThe application requesting accessMobile app, web app, server-side script
Authorization ServerIssues tokens after authenticating the resource owner and obtaining authorizationIdP (Okta, Auth0, Azure AD)
Resource ServerHosts the protected resources, accepts and validates access tokensAPI server

OAuth 2.0 Grant Types

Grant TypeUse CaseSecurity LevelRefresh Tokens?
Authorization CodeServer-side web apps, mobile apps (with PKCE)HighYes
Authorization Code + PKCEPublic clients (SPA, mobile) — recommendedVery HighYes
Client CredentialsServer-to-server, machine-to-machineHighYes (if configured)
Device CodeCLI tools, smart TVs, IoT devices with no browserMediumYes (polling)
Refresh TokenObtain new access tokens without user interactionDepends on bindingN/A
Implicit (deprecated)Legacy SPAs — DO NOT USELowNo

Danger

The OAuth 2.0 Implicit grant (response_type=token) was deprecated in OAuth 2.1 due to security concerns — access tokens are exposed in the URL fragment, cannot be securely stored in SPAs, and are vulnerable to interception. Use Authorization Code + PKCE instead.

Authorization Code + PKCE — The Gold Standard

PKCE (Proof Key for Code Exchange, pronounced “pixy”) extends the Authorization Code grant to make it secure for public clients that cannot protect a client secret.

┌─────────┐ ┌──────────────┐ ┌──────────────┐
│ Client │ │ Auth │ │ Resource │
│ (App) │ │ Server │ │ Server │
└────┬─────┘ └──────┬───────┘ └──────┬───────┘
│ 1. Generate code_verifier│ │
│ and code_challenge │ │
│ 2. Auth Request │ │
│ + code_challenge ─────→ │
│ 3. User authenticates │ │
│ ←─────────────────────│ │
│ 4. Authorization code │ │
│ ←─────────────────────│ │
│ 5. Auth code │ │
│ + code_verifier ─────→│ │
│ 6. Verify code_verifier │ │
│ matches code_challenge│ │
│ 7. Access Token + RT ────→ │
│ 8. Access Token ────────────────────────────────→│
│ 9. Protected resource ──────────────────────────→│
│ ←─────────────────────────────────────────────│

Why PKCE is critical: The code_verifier is a cryptographically random string generated by the client. Even if an attacker intercepts the authorization code, they cannot exchange it for tokens without the code_verifier. This protects against authorization code interception attacks.

Client Credentials Grant — Machine-to-Machine

Used when the client (typically a server-side service) needs to access its own resources, not on behalf of a user. No user involvement.

Service A ──→ Token Endpoint (client_id + client_secret) ──→ Access Token ──→ Service B API

Security considerations:

  • Client secrets must be stored securely (HSM, secrets manager, environment variables)
  • Use client authentication methods: client_secret_basic, client_secret_post, or private_key_jwt
  • private_key_jwt is the most secure — uses asymmetric key pair instead of shared secret
  • Rotate client secrets regularly and immediately after any suspected compromise

OAuth 2.0 Tokens

Access Tokens

Access tokens are credentials used to access protected resources. They represent the authorization granted to the client.

PropertyOpaque TokenJWT (Structured Token)
FormatRandom stringJWT (JSON Web Token)
ValidationIntrospection endpoint requiredSelf-validating (signature + claims)
PayloadNone visibleJSON claims (sub, scope, exp, iss, aud)
PerformanceFast to issue, slowest to validate (needs introspection)Moderate on both — validation is local but parsing overhead
RevocationImmediate (server-side state)Delayed (until token expires) unless blacklist is checked
SizeSmall (16-32 bytes)Larger (compressed JWTs ~1-2KB)

Refresh Tokens

Refresh tokens allow the client to obtain new access tokens without requiring the user to re-authenticate.

Best practices:

  • Bind refresh tokens to the client (sender-constrained)
  • Use refresh token rotation — issue a new refresh token with each use; invalidate the previous one
  • Set absolute expiration (e.g., 90 days) even with rotation
  • Detecting refresh token reuse strongly indicates token theft — revoke all tokens for the user

OpenID Connect — The Identity Layer

OpenID Connect extends OAuth 2.0 with the openid scope. When a client requests the openid scope, the authorization server returns an ID Token — a JWT containing identity claims about the authenticated user.

OIDC Scope-to-Claim Mapping

ScopeAccessClaims Returned
openidRequired — indicates OIDC requestsub (subject identifier)
profileUser profile informationname, given_name, family_name, preferred_username
emailEmail addressemail, email_verified
addressPhysical addressaddress (JSON object)
phonePhone numberphone_number, phone_number_verified
offline_accessRefresh tokenEnables refresh token issuance

OIDC Flows

Flowresponse_typeClient TypePKCE Required?
Authorization Code FlowcodeConfidential (web server)Recommended
Authorization Code + PKCEcodePublic (SPA, mobile)Required
Hybrid Flowcode id_token, code token, code id_token tokenBothRecommended
Implicit Flow (deprecated)id_token tokenPublic (legacy SPA)N/A — DO NOT USE

ID Token Validation

When a client receives an ID Token, it MUST perform the following validations:

  1. Signature verification — Validate the JWT signature using the IdP’s public key (fetched from the JWKS endpoint)
  2. Issuer validation — The iss claim must match the expected IdP issuer identifier
  3. Audience validation — The aud claim must contain the client’s client_id
  4. Expiration check — The token must not be expired (check exp claim)
  5. Issued-at check — The token must not be in the future (check iat claim, with acceptable clock skew)
  6. Nonce validation — If a nonce was sent in the request, it must match the nonce claim in the ID Token

Token Binding and DPoP

OAuth 2.0 Token Binding

Token binding cryptographically binds tokens to the TLS connection, preventing token export and replay. When a token is bound to the TLS connection, an attacker who steals the token cannot use it from a different device.

DPoP (Demonstration of Proof-of-Possession)

DPoP is a newer mechanism that binds access and refresh tokens to a public-private key pair held by the client. The client proves possession of the private key when using the token.

POST /token HTTP/1.1
Host: auth.example.com
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7...
// DPoP proof JWT signed with client's private key
// Contains: jti (unique ID), htm (HTTP method), htu (HTTP URI), iat (issued at)

Tip

DPoP provides sender-constrained tokens without the TLS layer complexity of token binding. For greenfield deployments, implement DPoP to prevent token replay attacks. For existing deployments, prioritise DPoP for high-value API endpoints.

OAuth 2.1 — The Consolidated Standard

OAuth 2.1 consolidates and simplifies OAuth 2.0 by removing security‑weakening options:

ChangeOAuth 2.0OAuth 2.1
Implicit grantAllowedRemoved
Resource Owner Password grantAllowed (deprecated)Removed
Client Credentials grantNo restrictionsSender-constrained recommended
PKCEOptional for authorization codeRequired for public clients
Refresh tokensNo binding requirementSender-constrained required
Redirect URIsPattern matches allowedExact match required

Key Takeaways

  • OAuth 2.0 is a delegated authorization framework with four roles (resource owner, client, authorization server, resource server) — it is NOT an authentication protocol
  • OIDC adds an identity layer to OAuth 2.0 via the ID Token (JWT), enabling secure user authentication on top of OAuth 2.0’s authorization model
  • Authorization Code + PKCE is the recommended grant for all public clients (SPA, mobile) — PKCE prevents authorization code interception attacks
  • Access tokens can be opaque (server-side validation) or JWT (self-validating); refresh tokens enable ongoing access without re-authentication
  • Token binding and DPoP prevent token replay by cryptographically binding tokens to the client or TLS connection
  • OAuth 2.1 removes security-weak options (implicit grant, password grant) and requires PKCE for public clients and sender-constrained refresh tokens