Hermes Wiki
Architecture/Fundamentals/oauth2-and-oidc

OAuth 2.0 and OpenID Connect

Concept

OAuth 2.0 and OpenID Connect (OIDC) solve two different problems that get conflated constantly, and the conflation is where most integration bugs and security reviews go wrong. OAuth 2.0 is an authorization framework — it lets a user grant a third-party application limited access to their resources on another service, without ever handing that application their password. OIDC is a thin identity layer built directly on top of OAuth 2.0 — it answers authentication ("who is this user") by adding a standardized id_token (a signed JWT) to the OAuth flow. OAuth alone was never designed to prove identity; using a bare OAuth access token as a login credential was a common early mistake OIDC exists specifically to close.

The core OAuth dance has four parties: the resource owner (the user), the client (the app requesting access), the authorization server (issues tokens, e.g. Google/Okta/Auth0), and the resource server (the API being accessed, which validates the token). The Authorization Code flow is the standard shape for anything with a backend: the client redirects the user to the authorization server, the user authenticates and consents, the authorization server redirects back with a short-lived one-time authorization code, and the client's backend exchanges that code — server-to-server, with its own client secret — for an access token (and optionally a refresh token). The access token is what gets sent to the resource server on subsequent API calls; the code itself is a throwaway intermediate that's never usable twice. For public clients that can't hold a secret (mobile apps, SPAs), PKCE (Proof Key for Code Exchange) replaces the client secret with a per-request cryptographic challenge, closing the interception risk that a static secret can't protect against in an unauthenticated client.

Tradeoffs

Flow / grant Fits Security profile Common misuse
Authorization Code (+ PKCE) Server-rendered apps, SPAs, mobile apps Strong — code is short-lived and single-use, tokens never touch the browser's URL bar Skipping PKCE on a public client, or storing the client secret in a mobile binary
Client Credentials Machine-to-machine, no end user Strong for its scope — no user context at all, just service identity Using it where a real user identity is actually required downstream
Implicit (deprecated) Legacy SPAs before PKCE existed Weak — access token returned directly in the URL fragment, exposed to browser history and referrer leaks Still found in old codebases; should be migrated to Auth Code + PKCE
Resource Owner Password Credentials Legacy first-party migrations only Weak — the client handles the user's raw password directly, defeating OAuth's core purpose Any third-party or modern app using it at all

The deeper tradeoff is between token lifetime and blast radius. A long-lived access token means fewer re-authentication round trips but a bigger exposure window if it leaks; the standard mitigation is a short-lived access token (minutes) paired with a longer-lived refresh token that's used to mint new access tokens without re-prompting the user — narrowing the window an attacker can act in while a stolen access token, without preserving the ability to keep using a stolen refresh token indefinitely (refresh tokens should be rotated and revocable).

When to use / when not to

  • Use OAuth 2.0 whenever a client needs delegated access to a resource on the user's behalf without holding their credentials — "let this app read your calendar," "let this app post on your behalf."
  • Use OIDC specifically when the goal is authentication — "who is logging in" — layered on top of the same infrastructure; don't try to repurpose a bare OAuth access token as a login signal, since nothing in the OAuth spec guarantees the token proves identity or is even meant to be introspected by the client.
  • Use Client Credentials grant for pure service-to-service calls with no user in the loop — it's simpler and avoids modeling a user that doesn't exist.
  • Don't build a custom token/session scheme from scratch when integrating with third-party identity providers is the actual requirement — reinventing this is a well-trodden path to a security bug that's already been solved and audited in the standard.
  • Don't use the Resource Owner Password grant for anything except a first-party legacy migration path being actively deprecated — it exists in the spec for backward compatibility, not as a recommended pattern.

Common pitfall

Treating the OAuth access token as proof of identity. An access token only proves the bearer has some permission scope on the resource server — it says nothing verifiable about who the user is unless the resource server was specifically designed to encode and check that. Teams that skip OIDC and try to identify users purely from an OAuth access token end up building fragile, non-standard identity inference on top of a token that was never meant to carry that guarantee — the fix is the id_token OIDC adds, which is a signed, verifiable JWT specifically meant to be consumed as an identity assertion.

Principal Engineer Lens

The authorization-vs-authentication distinction is a fast litmus test in an architecture review: ask "is this system granting access, or proving identity, or both" and watch whether the design cleanly separates the two concerns or conflates them into one token doing double duty. In Fintech and Capital Markets contexts specifically, this distinction has direct compliance weight — regulators and auditors expect authentication (who) and authorization (what they can do) to be independently verifiable and independently revocable, which is exactly what the OAuth/OIDC split gives you for free if implemented correctly, and exactly what gets murky if a team improvises around it.

Sources:

Hermes Wiki