Skip to main content
Authentication, encryption, network security, application security, and secure system design.

Security

Authentication, encryption, network security, application security, and secure system design.

Identity & Access Management Patterns

The sec-auth topic covers authentication (who is the user?) and the models of authorization (which authorization framework are we using?). This topic is the implementation patterns beneath those models — what an RBAC system actually looks like as tables, how OAuth flows actually behave in edge cases, where JWT validation breaks, and how tokens get replayed when the lifecycle is sloppy.

Authorization Models

ModelDecision ruleScaling propertyTypical fit
ACL (access control list)Per-object list of permitted usersO(users × objects) — explodes past ~10k objectsNetwork filesystems; single-team wiki
RBAC (role-based)User → role → permissionsO(users × roles + role × permissions) — scales with role count, not objectsThe dominant model in business apps; SaaS multi-tenant
ABAC (attribute-based)Decision over attributes of user, resource, action, environmentO(rules) — but the decision logic is programmableTight security zones; multi-jurisdictional healthcare
ReBAC (relationship-based)Tuple-based / OPA-style relationshipsO(relationships) for n-dimensional sharingGoogle Drive / GitHub repo sharing; “user A is a viewer of team B which is a member of org C which owns doc D”

The honest take: RBAC is the right default. ABAC surfaces in the rare systems that genuinely compute the decision (a patient’s doctor-can-see-this-record depends on state, age, and consent). ReBAC (à la Google Zanzibar / SpiceDB / OPA) is the answer to “I need to model organizational sharing relationships declaratively” — the auth system becomes a graph database of (subject, relation, object) tuples.

A platform with 500 employees, an HR system with 5 roles, and an SaaS app with 50 user roles: RBAC at every layer; the role hierarchy becomes the management currency. Reaching for ABAC at that scale is over-engineering; reaching for ReBAC is right when the permission graph is itself a graph.

OAuth 2.0: Grants and Scopes

OAuth 2.0 is the delegated authorization protocol: a user grants a third party access to act on their behalf, scoped to specific operations, without sharing their password.

Grant typeShapeUse case
Authorization Code (with PKCE)Browser redirect → auth server → code → token exchangeBrowser and mobile apps (PKCE mandatory for public clients since OAuth 2.1)
Client CredentialsClient authenticates with its secret; gets token for itselfService-to-service (no user involved)
Device CodeUser authorizes on a separate deviceSmart TVs, IoT, CLI tools on headless boxes
Refresh TokenExchange long-lived refresh token for a new short-lived access tokenStandard across all flows; avoids re-prompting the user
Implicit grant (deprecated)Token returned directly in the redirectRemoved in OAuth 2.1; never use

A scope is the named permission the user grants (“read:profile”, “write:posts”). Two production rules:

  • Scopes are additive and orthogonal — never readwrite (a real bug seen in production: scope doesn’t separate read and write, so a read-only app gets write).
  • Scopes are user-consented at the time of authorisation — requesting 30 scopes panics the user; the trade-off of asking only for what the feature needs pays in completion rate.

OpenID Connect: The SSO Layer

OAuth 2.0 is authorization. OpenID Connect (OIDC) is authentication layered on top — the user proves who they are via an identity provider (Google, Okta, Auth0), and the relying party gets a verifiable ID token with their identity claims.

OAuth 2.0OIDC
Authorises a client to act on behalf of a userAuthenticates a user to a client
Issues an access token (opaque, for the resource server)Issues an ID token (a JWT containing user claims)
No defined user identityStandardised user identity claims (sub, email, name)
No standard /userinfo endpointStandardised /userinfo endpoint

The classic “Sign in with Google” button is OIDC: the browser redirects to Google, the user consents, Google returns an ID token that the application verifies, and the user is logged in. The access token from the same flow can also drive downstream API calls (“Sign in with Google and access my Drive”), which is why OIDC is layered on OAuth, not a separate protocol.

JWT Validation Pitfalls

A JWT is a JSON-signed token in three base64 parts: header.payload.signature. Validation is deceptively easy to get wrong. The standard bugs:

PitfallWhat happensThe fix
alg: none acceptedToken signed with no signature is accepted as validWhitelist the algorithm; reject none
RSA / HMAC confusionAttacker signs an RSA-expected token with HMAC using the RSA public key as the secretBind algorithm to key type in validator; library choice: well-audited only
Wrong issuer / audienceA token minted for auth-A is presented to auth-B and acceptedValidate iss and aud against expected values
Expired token acceptedLibrary not enforcing expReject if exp < now; check at request time, not just at token extraction
Wrong clockValidator’s clock skew lets expired tokens passBound exp - now to a clock-skew tolerance window; sync clocks via NTP
No key rotationKey compromise invalidates all tokens; rotation is manualUse a JWKS endpoint; rotate keys with overlap; old keys valid for exp_grace_period

The deepest horror: the library that does “valid JWT?” without verifying alg, iss, aud, exp is itself a security bug. JWT validation is three nested checks; skipping any of one is the most common production vulnerability class for token-bearing systems.

Token Lifecycle and Replay

A token is a bearer instrument: whoever holds it can use it, exactly like cash. Three lifecycle properties:

  • Short-lived access tokens — minutes, not days; the longer the access token’s TTL, the larger the replay-window damage if it is leaked.
  • Rotating refresh tokens — every time a refresh token is used to mint a new access token, the old refresh token is invalidated and a new one is issued. A replayed refresh token detected (used twice in a row) is the signal that a token has been stolen; the session is terminated.
  • Binding to client — tokens bound to a specific client via PoP (Proof-of-Possession) or DPoP (Demonstrating Proof-of-Possession) cannot be replayed from a different client; this is the upgrade path past bearer-token fragility.

The pattern of rotating refresh tokens (original introduced by OAuth 2.0, sharpened in OAuth 2.1) is the infrastructural defence against token leaks, and is the most-ignored single property in token-handling code.

Practice Trajectory

  1. Take an RBAC system you operate. List the roles; identify one role bloat case (a role permission that nobody actually needs). Remove it.
  2. Sketch the OAuth grant types appropriate for: (a) a CLI tool that connects to your SaaS; (b) a server-to-server worker calling an API; (c) a React SPA calling your own backend. Justify each.
  3. Audit a JWT validator in your codebase against the six pitfalls table. Patch any gap.
  4. Implement refresh-token rotation in your token endpoint. Trace what happens when a stolen refresh token is replayed (both attempts observed; session terminated).
  5. Pick an SSO flow you have used. Identify at which step the ID token is verified, and what fields must be checked for the user to be considered logged in.

When It’s the Right Tool

SituationTakeaway
Most business authorisationRBAC is the right default; reach for ABAC / ReBAC only when RBAC genuinely can’t express the rule
Browser/mobile client → your APIOAuth Authorization Code with PKCE
Service-to-serviceClient Credentials grant; mTLS or JWT for service identity
Single sign-on across appsOIDC; the ID token’s sub is the cross-app user identity
Bearer tokens you cannot afford to leakAdd token binding (DPoP); rotate refresh tokens; keep access-token TTL in minutes