Leer en español · Lire en français · Auf Deutsch lesen
Section 8.3 of 8.8 · Advanced · 26 min read
Identity and access: authentication, authorisation, OAuth 2.0 and OpenID Connect
Video lesson
5 min · narrated, with captionsListen only (audio)
Read the transcript
Every request raises two questions: who is calling, and what may they do? This lesson shows how architects answer both, for people and for services.
Think of a large office building. At reception you show a photo ID and get a badge. That's authentication: proving who you are. The badge then opens some doors and not others. That's authorisation: deciding what you may do. A courier collecting a parcel for you gets a limited pass for the post room, only today. OAuth works like that, for apps. And the building's own machines need badges too, so they can prove to each other that they're genuine.
Authentication is best centralised in one identity provider that every application trusts, so that password rules, multi-factor authentication and account recovery are built once. Authorisation is distributed. Only the ordering service knows who owns an order, so the final decision about an order must be made there. Most access control breaches come from confusing the two: an endpoint checks that the token is valid, then returns whatever order it's asked for.
NIST's guidelines favour long passwords over rules about digits and symbols, and require a check against breached passwords. They forbid forcing changes on a schedule. Multi-factor authentication stops most attacks with leaked passwords. But no one-time code resists phishing, because a fake site can relay it at once. A passkey resists phishing. The device signs a challenge with a private key bound to the real website, and the server holds only the public key. And watch account recovery. If a lost passkey can be replaced by clicking an emailed link, the whole system is only as strong as that email account.
After login, a server-side session keeps the details on the server and gives the browser a random identifier in a cookie. Revoking it is immediate. A self-contained token, usually a JSON Web Token, is signed by the issuer, so any service can check it without a lookup. But it can't be revoked before it expires. So keep them short-lived, fix the signing algorithm in code, and check the issuer, audience and expiry, not just the signature. And don't keep tokens in browser storage, where any script on the page can read them.
OAuth 2.0 lets an application act for a user without learning the user's password. Here are the four parties: the user's browser, the client app, the authorisation server, and the resource server that holds the data. Apps acting for a user should use the authorisation code flow with Proof Key for Code Exchange, or PKCE. First, the client makes a random secret, the verifier, and works out its hash, the challenge. The client sends only the challenge to the authorisation server. The user logs in, with a passkey here, and consents. The browser is redirected back to the client with a short-lived code. The client exchanges that code for tokens in a direct request, sending the original verifier. The server checks that its hash matches the challenge. The client receives an access token and calls the API with it. An attacker who intercepts the code can't redeem it, because the verifier never left the client.
With no user involved, such as a partner's system calling the platform, a service uses the client credentials grant. OAuth on its own doesn't tell the client who the user is. OpenID Connect adds that, with an ID token stating who logged in, for which client, and when. The rule of thumb: the ID token is for the client, to know who logged in. The access token is for the API, to authorise calls. And between services, workload identity replaces long-lived shared keys with short-lived identities issued by the platform.
Restaurants range from single cafés to large chains. With roles alone, every check needs to know which branch, and you end up with thousands of roles. Relationship-based access control stores relationships instead: a manager manages a branch, a branch belongs to a restaurant, an order belongs to a branch. Rules follow the relationships. A branch manager may edit that branch's menu, and so may the owner of the restaurant. A courier may see the pickup address only while the delivery is assigned to them. When it completes, the link is removed, and so is the access. And a refund limit of twenty pounds depends on an attribute of the request, so it's written as an attribute-based policy. Real systems combine models like this. As for enforcement, the API gateway rejects requests without a valid token or scope. Each service then asks a policy engine the object level question. That fine check is the one teams forget.
The full section has a guide to choosing OAuth flows and the authorisation models compared. Next, in Section eight point four, we look at protecting data. See you there.
What you need to know
- Authentication establishes who is calling and is best centralised in one identity provider; authorisation decides what they may do to which object and must be enforced where the data is, in every service.
- NIST SP 800-63B (revision 4, 2025) favours length over composition rules, requires blocklist checks against common and breached passwords, forbids forced periodic changes and expects phishing-resistant options such as passkeys.
- Server-side sessions are easy to revoke; self-contained JWTs scale but cannot be revoked before expiry, so keep them short-lived, pin the algorithm, check issuer, audience and expiry, and keep them out of localStorage.
- OAuth 2.0 (RFC 6749) delegates limited access through tokens; users' apps should use the authorisation code flow with PKCE (RFC 7636), services client credentials; OAuth 2.1 is still an Internet-Draft in 2026.
- OpenID Connect adds an ID token telling the client who logged in; the ID token is for the client and the access token for the API.
- RBAC, ABAC and relationship-based access control (Google Zanzibar, 2019) suit different needs; policy engines such as OPA separate decision from enforcement, and workload identity (SPIFFE, mTLS) replaces shared service secrets.
Authentication and authorisation
Every request to the food-delivery platform raises two separate questions. Authentication asks who is this? and is answered by evidence: a password, a passkey, a certificate, a signed token. Authorisation asks may they do this, to this, now? and is answered by policy: this customer may read this order because they placed it; this courier may see this pickup address because the delivery is assigned to them. HTTP keeps them apart too: 401 Unauthorized means the request lacks valid authentication, while 403 Forbidden means the caller is known but not allowed.
The distinction matters architecturally because the two are solved in different places. Authentication is best centralised in one identity provider (IdP) that all applications trust, so that password rules, multi-factor authentication, account recovery and lockout are implemented once. Authorisation is inherently distributed: only the ordering service knows who owns an order, so the final decision about an order must be made there, even if coarse checks happen earlier at the API gateway. Most access-control breaches in the OWASP Top 10 come from confusing the two: an endpoint that checks the token is valid and then returns whatever object ID it is given.
Passwords, multi-factor authentication and passkeys
Passwords remain the most common authenticator, and NIST's Digital Identity Guidelines are the most widely followed rules for them. Revision 4 of SP 800-63B, published in July 2025, reverses several long-standing habits. Length matters more than composition: a password used as the only factor must be at least 15 characters long (at least 8 when it is used only as part of multi-factor authentication), and verifiers should accept at least 64 characters, including spaces and Unicode. Verifiers must not impose composition rules such as requiring a digit and a symbol, which make passwords harder to remember without making them much harder to guess. They must check new passwords against a blocklist of common, expected and breached passwords. They must not force periodic changes, only a change when there is evidence of compromise. They must allow password managers and should allow pasting, must not offer password hints readable before login, and must not prompt for security questions. Failed attempts must be rate-limited.
Multi-factor authentication (MFA) combines factors of different kinds: something you know (a password), something you have (a phone or security key) and something you are (a fingerprint, usually used only to unlock a device). It defeats most credential stuffing, where attackers try username and password pairs leaked from other sites. Not all second factors are equal: one-time codes sent by SMS can be stolen by SIM swapping, and no one-time code, whether from SMS or an authenticator app, resists phishing, because a user can be tricked into typing it into a fake site that relays it immediately. NIST's guidelines therefore require services at authentication assurance level 2 to offer at least one phishing-resistant option, and level 3 to use one.
A passkey is the phishing-resistant option most users can actually use. Passkeys are FIDO2 credentials, built on the W3C Web Authentication API (WebAuthn) and the FIDO Alliance's Client to Authenticator Protocol (CTAP). At registration the user's device creates a new key pair for that website; the server stores only the public key. At login the server sends a random challenge, and the device signs it with the private key after the user unlocks it with a fingerprint, face or PIN. Because the browser binds the credential to the website's origin, a look-alike phishing site cannot obtain a valid signature, and because the server holds no shared secret, a database breach yields nothing an attacker can replay. Passkeys may be device-bound (on a hardware security key) or synced between a user's devices by a platform or password manager; NIST's 2025 guidance accepts synced passkeys at level 2, while level 3 requires a key that cannot be exported.
The architectural weak point of every authentication scheme is account recovery. If a lost passkey can be replaced by clicking an emailed link, the strength of the whole system is the strength of the email account. Recovery flows deserve their own threat model, rate limits, notifications to the user's other devices and, for high-value accounts, delays or human checks.
Sessions and tokens
Once a user has authenticated, the system must recognise their later requests without asking again. There are two basic designs. In a server-side session the server stores the session (user, expiry, perhaps roles) and gives the browser a long random session identifier in a cookie. In a self-contained token design, the issuer signs a token carrying the claims, typically a JSON Web Token (JWT, RFC 7519), and any service holding the issuer's public key can validate it without a lookup.
Server-side sessions compared with self-contained tokens
| Aspect | Server-side session | Self-contained token (JWT) |
|---|---|---|
| Where state lives | In a session store on the server; the browser holds only a random identifier. | In the signed token; the server keeps nothing per user. |
| Revocation | Delete the session: immediate. | Not possible before expiry without a denylist or a lookup, so lifetimes must be short. |
| Scaling across services | Needs a shared session store or sticky routing. | Any service can validate the signature locally. |
| Size on the wire | A small cookie. | Hundreds of bytes to kilobytes on every request. |
| Typical use | Browser sessions for web applications and backends for frontends. | Access tokens for APIs, mobile apps and service-to-service calls. |
| Main risks | Session fixation and cross-site request forgery (mitigated by regenerating the ID at login and SameSite cookies). | Theft through script injection if stored in browser storage; validation mistakes; stale claims. |
For browser applications, a server-side session in a cookie marked HttpOnly (invisible to JavaScript), Secure (HTTPS only) and SameSite is hard to beat. Single-page applications increasingly use a backend for frontend (BFF): the browser holds only a session cookie for its own small backend, which holds the OAuth tokens and calls the APIs on its behalf, an approach the IETF OAuth working group's guidance for browser-based applications recommends. JWTs shine between services and in mobile apps, where a stateless check at each hop avoids a central bottleneck.
import jwt # PyJWT
from jwt import PyJWKClient
ISSUER = "https://id.fooddelivery.example/"
jwks = PyJWKClient(ISSUER + ".well-known/jwks.json") # issuer's public keys
def verify_access_token(token: str) -> dict:
signing_key = jwks.get_signing_key_from_jwt(token)
return jwt.decode(
token,
signing_key.key,
algorithms=["RS256"], # pinned: never read from the token header
audience="orders-api", # the token must be meant for this API
issuer=ISSUER,
options={"require": ["exp", "iat", "sub"]},
) # raises an exception on any failure: fail closedOAuth 2.0: delegated authorisation
OAuth 2.0 (RFC 6749, 2012) solves a specific problem: letting an application act on a user's behalf without learning the user's password. Before it, a service that wanted to import your contacts asked for your email password. OAuth defines four roles: the resource owner (the user), the client (the application wanting access), the authorisation server (which authenticates the user, asks for consent and issues tokens) and the resource server (the API holding the data). The client receives an access token limited by scopes (such as orders:read), a lifetime and an audience, and often a refresh token to obtain new access tokens without asking the user again.
OAuth defines several ways, called grants, to obtain a token. For any application acting for a user, whether a server-side web app, a single-page app or a mobile app, the recommended grant is the authorisation code flow with PKCE (Proof Key for Code Exchange, RFC 7636, 2015). The client first creates a random code_verifier and sends only its SHA-256 hash, the code_challenge, when it redirects the user to the authorisation server. After the user logs in and consents, the authorisation server redirects back with a short-lived authorisation code. The client then exchanges the code for tokens in a direct back-channel request, sending the original verifier; the server checks that its hash matches the challenge. An attacker who intercepts the code, for example a malicious mobile app registered for the same redirect address, cannot redeem it without the verifier, which never left the client.
The client credentials grant covers the case with no user: a service obtains a token with its own authority, for example the dispatch service calling a mapping partner's API, or a partner's system calling the platform's order-status API. The client should authenticate to the token endpoint with a private key (a signed JWT assertion) or mutual TLS (RFC 8705) rather than a shared secret. Two older grants are now discouraged: the implicit grant, which returned tokens in the browser's URL, and the resource owner password credentials grant, which had the client collect the user's password and so defeated the purpose of OAuth. RFC 9700, the OAuth 2.0 Security Best Current Practice published in January 2025, records these lessons, including exact matching of redirect addresses and sender-constrained tokens.
OAuth 2.1 consolidates OAuth 2.0 and these best practices into one document: PKCE is required for the authorisation code flow, the implicit and password grants are removed, redirect addresses must match exactly and bearer tokens may no longer be sent in URL query strings. At the time of writing (October 2026) it is still an IETF Internet-Draft (draft 16, September 2026), not an RFC, but its rules already describe what well-run authorisation servers do.
Decision guide
Decision guide: which OAuth 2.0 flow?
For each kind of caller of the food-delivery APIs.
- Is a person present, and does the application act on their behalf?YesUse the authorisation code flow with PKCE, for web, single-page and mobile apps alike; never the implicit or password grants.NoGo to the next question.
- Is the device unable to show a browser or hard to type on, such as a restaurant's kitchen display?YesUse the device authorisation grant (RFC 8628): the device shows a short code that the user approves on their phone.NoGo to the next question.
- Is it one of your own services calling another inside your platform?YesPrefer workload identity (mutual TLS with platform-issued identities); if the API expects OAuth tokens, use client credentials with key-based client authentication.NoGo to the next question.
- Is it a partner's system calling your API with its own authority?YesUse client credentials with narrowly scoped, short-lived tokens, one client per partner and per-partner rate limits.NoRevisit the requirement: a design in which your client needs a user's password is a warning sign.
OpenID Connect, single sign-on and SAML
OAuth issues access tokens for APIs; it does not, by itself, tell the client who the user is. Using an access token as proof of login is a well-known mistake, because a token issued to one application can be replayed to another that does not check its audience. OpenID Connect (OIDC, Core 1.0, 2014) adds the missing identity layer. With the openid scope, the authorisation server, now acting as an OpenID provider, also returns an ID token: a signed JWT for the client, stating the issuer, the user's stable identifier (sub), the audience (the client's ID), issue and expiry times, a nonce that ties it to this login and, optionally, how and when the user authenticated. OIDC also standardises a user information endpoint and discovery documents that publish the provider's endpoints and signing keys. The rule of thumb: the ID token is for the client, to know who logged in; the access token is for the API, to authorise calls.
Single sign-on (SSO) follows naturally: once a user has a session with the identity provider, every application that trusts it can log them in without another password prompt, and disabling the account in one place cuts access everywhere. In enterprises, SSO often still uses SAML 2.0 (an OASIS standard from 2005), which exchanges signed XML assertions through the browser. The food-delivery platform might use OIDC for its own apps and accept SAML from large restaurant chains that want their staff to log in to the restaurant portal with their corporate accounts. Provisioning and deprovisioning accounts across systems is usually automated with SCIM (RFC 7643 and 7644).
Authorisation models: RBAC, ABAC and relationships
Authentication tells the system who is calling; an authorisation model decides what they may do. Three models dominate, and real systems usually combine them.
Three authorisation models
| Model | How it decides | Strengths | Weaknesses |
|---|---|---|---|
| Role-based (RBAC) | Permissions are granted to roles; users are assigned roles. Formalised by David Ferraiolo and Richard Kuhn at NIST in 1992. | Simple to understand and audit; maps to job functions such as support agent. | Cannot express "only their own" without extra rules; scoping by branch or market leads to role explosion. |
| Attribute-based (ABAC) | A policy evaluates attributes of subject, resource, action and environment; described in NIST SP 800-162 (2014). | Very expressive: market, data classification, time, device posture, amount. | Harder to answer "who can access this?"; policies can become opaque and slow. |
| Relationship-based (ReBAC) | Access follows relationships stored as a graph: a user manages a branch, a branch belongs to a restaurant, an order belongs to a branch. | Natural for sharing and hierarchies; scales to fine-grained, per-object permissions. | Needs a dedicated, consistent relationship store and careful modelling. |
Relationship-based access control is best known from Google's 2019 paper on Zanzibar, the global authorisation system behind Google Drive, Calendar, YouTube and many other products. Zanzibar stores relation tuples of the form object#relation@user, evaluates permissions by following them, and uses consistency tokens so that a permission check is never evaluated against data older than the content it protects, the so-called new enemy problem: removing someone from a document and then adding sensitive content must not let them see it. Open-source systems inspired by it include SpiceDB, OpenFGA and Ory Keto.
Whatever the model, it helps to separate the policy decision point (PDP), which evaluates policy and answers allow or deny, from the policy enforcement point (PEP), the code in the gateway or service that asks the question and enforces the answer. General-purpose policy engines such as Open Policy Agent (OPA, a graduated Cloud Native Computing Foundation project, with policies written in its Rego language) and Cedar (open-sourced by Amazon Web Services in 2023) let policy live in versioned files, be tested like code and be evaluated in-process or as a sidecar, close to the service. A sensible layering on the platform is: the API gateway rejects requests without a valid token or the right scope (coarse), and each service decides object-level questions with data only it has (fine). Broken object-level authorisation is the first risk in the OWASP API Security Top 10 (2023 edition) precisely because the fine check is the one teams forget.
Workload identity: when the caller is a service
Services authenticate to each other far more often than people log in, yet service credentials are often the weakest: a long-lived API key in an environment variable, shared by several services and never rotated. If that key leaks through a log, a repository or a container image, the attacker becomes the service. Workload identity replaces such secrets with identities issued by the platform to the running workload, after the platform has verified what the workload is.
The open standard is SPIFFE (Secure Production Identity Framework for Everyone), a graduated Cloud Native Computing Foundation project. It names each workload with a URI such as spiffe://fooddelivery.example/ns/prod/sa/orders and issues a short-lived, automatically rotated document proving it, called an SVID, usually an X.509 certificate (or a JWT). Its reference implementation, SPIRE, attests the node and the workload (for example its Kubernetes namespace and service account) before issuing the identity. Services then use the certificates for mutual TLS, so the payments service knows that the caller is really the ordering service, and can authorise by identity. Cloud platforms offer equivalents (roles for workloads, managed identities, workload identity federation), and CI systems such as GitHub Actions can exchange a signed OIDC token for short-lived cloud credentials, so pipelines need no stored keys. How these identities are used to build a network with no implicit trust is the subject of zero trust.
Check your understanding
An API returns 403 to a caller with a valid token. What does that tell you?
The caller was authenticated but is not authorised for this action or object; 401 would mean missing or invalid authentication.
What does PKCE protect against in the authorisation code flow?
Interception or injection of the authorisation code: without the code verifier, which never travels in the browser redirects, a stolen code cannot be exchanged for tokens.
Why should a service not accept an OpenID Connect ID token as an API access token?
The ID token is addressed to the client (its audience is the client ID) to tell it who logged in; APIs should accept only access tokens issued for them, checked for audience and scope.
Why does a role such as manager_branch_1742 suggest the wrong authorisation model?
It encodes a relationship (manager of a particular branch) as a role, which leads to role explosion; relationship-based or attribute-based rules express it directly.
Sources and further reading
- RFC 6749: The OAuth 2.0 Authorization Framework
- RFC 7636: Proof Key for Code Exchange by OAuth Public Clients
- RFC 9700: Best Current Practice for OAuth 2.0 Security
- NIST SP 800-63B-4: Authentication and Authenticator Management
- Zanzibar: Google's Consistent, Global Authorization System (USENIX ATC 2019)
Have a question about this section? ArchitectBot, the course’s AI study assistant, answers from the course first.
Ask: “Should our single-page app keep OAuth tokens in the browser, or use a backend for frontend, and what changes in the architecture if we switch?”