Identity provider
Proves identity. It authenticates Maya and issues a signed statement about the result.
An example-driven field guide
Learn one common web architecture by growing Maya’s tiny sign-in into a secure CRUD application—one redirect, credential, and trust decision at a time.
The durable idea: the identity provider proves who signed in, your server keeps OAuth and session secrets, and your API decides what that person may do.
Chapter 1 · Mental model
“Login” looks like one action in the UI. Underneath, three systems make three different promises. Keeping those promises separate is the key to understanding the architecture.
Proves identity. It authenticates Maya and issues a signed statement about the result.
Creates a local session. It validates the provider result, maps Maya to a local user, and remembers her browser.
Authorizes each action. It checks whether user-7 may read or change a specific application record.
Do not collapse the jobs: a valid provider login does not automatically grant access to every record in your application.
Chapter 2 · Three different jobs
These terms often appear together, but they are not synonyms. Our example uses all three in sequence.
A framework for delegated access. It defines how a client obtains limited authority to call a protected resource.
An identity layer on OAuth. It adds an ID Token and rules that let the client learn who authenticated.
Your application’s own continuity mechanism. It is created after OIDC succeeds and is governed by your expiry and revocation rules.
Common mix-up: an ID Token is evidence for the OIDC client. It is not automatically the credential your browser should send to every application API.
Chapter 3 · Meet the system
Maya uses a browser to sign into Tasks. Tasks trusts an external provider, but owns its own users, permissions, sessions, and data.
Follows redirects, sends the application cookie, and renders responses. Treat its runtime as observable and influenceable.
A confidential OAuth client. It runs OIDC, owns sessions, authenticates requests, and enforces business policy.
Stores local users, hashed session identifiers, permissions, and Maya’s task records.
Authenticates Maya, obtains consent when needed, and issues a one-time code plus signed identity claims.
Ownership and trust boundaries
Our recurring example: Maya signs into Tasks, then creates item-42: “Read RFC 9700.” Every later chapter adds detail to this same journey.
Chapter 4 · Grow the sign-in
Use the numbered buttons to grow the flow. Each stage adds one necessary responsibility without changing the story.
GET /auth/login
/callback?code=…
302 /authorize
POST /token
Set-Cookie: __Host-session
hash(cookie) + expiry
login + consent
303 callback?code=…
ID Token + access token
A top-level navigation begins the ceremony. Maya’s provider password never passes through Tasks.
Notice the two channels: redirects travel through the browser; code redemption is a direct server-to-provider request. Provider tokens do not need to enter browser JavaScript.
Chapter 5 · Follow credentials
The flow is easier to reason about when every artifact has one purpose, owner, audience, and lifetime.
Power does not come from the format: a JWT is not inherently an ID Token, access token, or session. Meaning comes from its issuer, audience, validation rules, and the protocol context.
Chapter 6 · Make a CRUD request
After sign-in, an ordinary same-origin request usually talks only to your application. The provider does not approve each new task.
The cookie is attached automatically; JavaScript also supplies CSRF evidence required by the server.
POST /api/items
Hash the opaque cookie, find an unexpired session, and resolve it to local user-7.
session → user-7
Check CSRF, account status, tenant, operation, and record-level policy before writing.
mayCreate(user-7)
Create item-42 with its owner, then return only the representation Maya may see.
201 { id: "item-42" }
Request
Response
The application session is now the bridge: it translates a browser request into a local user. OAuth does not replace your API’s authentication and authorization middleware.
Chapter 7 · Authorize the action
The provider says “this is Maya.” Tasks must still decide what Maya can do with each application object.
Validated identity
https://id.example
maya-314
Broken object-level authorization: filtering the UI is not enforcement. The API must derive the actor from the authenticated session and constrain every query or command.
Chapter 8 · Secret ownership
Use this matrix as the architecture’s invariant. “Briefly transports” is different from “is trusted to use.”
| Artifact | Browser | Tasks server | Database | Provider | Purpose |
|---|---|---|---|---|---|
| Provider password | No | No | No | Yes | Provider authenticates Maya |
| State + code | Briefly transports | Creates / validates | May store transaction | Binds / issues | Bind and return one login attempt |
| PKCE verifier | No in this pattern | Yes | May store protected | Receives on redemption | Bind code redemption |
| ID Token | Not required | Validates | Usually no | Issues | Identity assertion for client |
| Provider access token | Not required | Only if needed | Protected if retained | Issues | Call its intended resource API |
| App session cookie | Stores, HttpOnly | Validates | Stores hash / state | No | Authenticate Tasks requests |
| CRUD data | Authorized view | Enforces access | Stores | No | Application business state |
Browser-visible is not browser-owned: the browser must carry the authorization code and cookie, but application JavaScript need not be able to read either one.
Chapter 9 · Security controls
Security names become memorable when tied to the confusion or replay they prevent. No single control “secures OAuth.”
Correlates the returned authorization response to the browser’s initiating transaction.
Not a replacement for PKCE or nonce.
The authorization request sends a challenge; only the party holding the verifier can redeem the code.
Use S256; make the verifier high entropy.
Connects the validated ID Token to the authentication request and helps detect replay or mix-up.
Validate it, do not merely send it.
Register and compare exact callback URIs so a code is not delivered to an attacker-controlled endpoint.
Do not use broad wildcard callbacks.
Secure limits HTTPS; HttpOnly blocks JavaScript reads; SameSite constrains cross-site sending.
HttpOnly does not stop malicious JS from issuing requests.
Require CSRF evidence for state changes and use a strong content-security and output-encoding posture.
SameSite is defense in depth, not the whole design.
Verify the permitted signature algorithm and key resolved from the expected issuer’s metadata. Handle key rotation deliberately.
Validate issuer, audience and authorized party when applicable, expiry and time claims, nonce, and any authentication context your policy requires.
Chapter 10 · Failure paths
A secure flow is also a failure model: detect the problem where enough trustworthy context exists, then recover without widening access.
The callback returns state that does not match the short-lived transaction stored by Tasks.
The Tasks callback compares state before exchanging the authorization code.
Reject, invalidate the transaction, avoid token exchange, log safe context, and let Maya restart.
Detect: server validation. Respond: create no local session; do not trust unvalidated claims.
Detect: session middleware. Respond: return 401, clear the cookie, and require fresh sign-in.
Detect: before mutation. Respond: reject the request even if its cookie maps to Maya.
Detect: object-level policy or constrained query. Respond: deny without revealing sensitive existence.
Fail closed: provider or network failure may block new sign-ins, but it should never turn into a session or permission bypass.
Chapter 11 · Architecture variants
The main lesson describes a server-side backend-for-frontend pattern. Other constraints produce valid but materially different ownership models.
Primary example
Provider tokens and the PKCE verifier stay server-side. The browser presents an opaque, Secure, HttpOnly application cookie to the same-origin API.
Different ownership
The SPA runs Authorization Code + PKCE and holds tokens in a hostile user-agent environment. There is no client secret. Token storage, refresh, XSS, CORS, and API audience become first-class design concerns.
Delegated downstream access
Now the provider access token has an ongoing job. The server must request the right audience and scopes, protect refresh credentials, and validate authorization again at the resource API.
Architecture test: ask “which component is the OAuth client, which API is the resource server, and which credential crosses each boundary?” If those answers change, the threat model changes too.
Chapter 12 · Design checklist
A design is understandable when the team can answer these questions without relying on “the auth library handles it.”
Which component is the OAuth/OIDC client, and is it public or confidential?
Where are state, nonce, and the PKCE verifier created, stored, expired, and validated?
Which exact redirect URIs, issuers, audiences, algorithms, and scopes are accepted?
How does validated (issuer, subject) map to a durable local user?
What credential authenticates ordinary browser-to-API requests after sign-in?
How are sessions rotated, expired, revoked, disabled, logged out, and cleared?
Where are CSRF, XSS, CORS, cookie, and content-security defenses enforced?
Which layer enforces operation-, tenant-, and object-level authorization?
Final test: point to any credential and explain who creates it, who can read it, where it may be sent, what validates it, and when it stops working.
Chapter 13 · Continue learning
This page teaches one common architecture and intentionally omits provider-specific setup and cryptographic implementation detail. Use the standards for normative requirements.
Scope note: production choices depend on your provider, browser/API origins, downstream APIs, session model, platform threats, and current security guidance. This is a reasoning aid, not a complete threat model.