Tags: web-dev concept

OAuth and OpenID Connect

Date: 2026-08-17


OAuth 2.0 is delegated authorisation — letting an app act on your behalf without your password. OpenID Connect is a thin layer on top that adds authentication. Using OAuth alone to log people in is the classic mistake, because it answers a question you didn’t ask.


OAuth 2.0 lets a user grant an application limited access to their data on another service, without sharing credentials. OpenID Connect (OIDC) extends it with an identity token, making it usable for login.

OAuth 2.0     "this app may read your
              Google Calendar"
              → AUTHORISATION

OIDC          "this user is alex@example.com,
              verified by Google"
              → AUTHENTICATION

“Sign in with Google” is OIDC, not plain OAuth — Authentication vs Authorisation.

The cast

RESOURCE OWNER    the user
CLIENT            your application
AUTHORISATION     issues tokens
  SERVER          (Google, Shopify…)
RESOURCE SERVER   holds the data (the API)

The flow you should use

Authorisation Code with PKCE — for every client type, including server-side ones:

1  app redirects the user to the
   authorisation server
     + client_id, scope, redirect_uri,
       state, code_challenge

2  user authenticates and consents

3  redirect back with a short-lived
   AUTHORISATION CODE

4  app exchanges the code (server-side,
   with code_verifier) for tokens

5  app calls the API with the access token

Why the code, rather than the token, comes back through the browser: the code alone is useless without the exchange step, so a leaked redirect URL doesn’t leak the token.

PKCE (Proof Key for Code Exchange) adds a one-time secret proving the app exchanging the code is the one that started the flow. Originally for mobile apps; now recommended for all clients.

Flows to avoid

IMPLICIT           deprecated. Returned the
                   token in the URL fragment
                   — logged, leaked, cached

PASSWORD GRANT     the app collects the
                   user's password. Defeats
                   the entire purpose

CLIENT CREDENTIALS not for users at all —
                   machine-to-machine only.
                   Legitimate, different job

The parameters that are security controls

state          CSRF protection. Generate,
               store, verify on return.
               ← omitting it is a real
                 vulnerability, not a
                 formality

redirect_uri   must be EXACTLY pre-registered.
               Open redirects here are how
               tokens get stolen

scope          request the minimum. Users
               reject broad consent screens,
               and a leaked token does more
               damage

nonce          OIDC. Binds the ID token to
               your request

state and exact redirect_uri matching are the two that get skipped, and both are exploitable.

The tokens you get back

ACCESS TOKEN   call the API with this
               short-lived, opaque or JWT

REFRESH TOKEN  get a new access token
               long-lived, store securely,
               server-side only

ID TOKEN       OIDC only. A JWT describing
               WHO the user is
               ← for your app to read,
                 never to send to an API

The ID token is for you; the access token is for the API. Sending an ID token as a bearer credential is a common confusion.

The mistake worth naming

Using an access token as proof of identity. An access token says “the bearer may do X” — it doesn’t say who the bearer is, and it may have been issued to a different application entirely.

The consequence: an attacker with a token issued for their own app can present it to yours, and if you treat “the token works” as “this is that user”, you’ve authenticated them as someone else. This is why OIDC exists — the ID token is signed, audience-restricted, and verifiable as being for you.

Verification, if you consume tokens

signature      against the provider's
               published keys
iss            the expected issuer
aud            YOUR client id
exp / iat      not expired
nonce          matches yours

Use a maintained library. Hand-rolled JWT verification is a documented source of vulnerabilities — Sessions and Tokens.

Where you’ll meet it

Almost every platform integration in this vault: Shopify app authorisation, the Adobe and Google APIs, Klaviyo, and any “connect your account” flow. The flow is the same each time, which is the reason to learn it once — Shopify, Adobe Experience Cloud.