Guide

Authentication vs authorization explained

Every secure application answers two questions in strict order: who is this caller? and are they allowed to do that? The first is authentication (AuthN); the second is authorization (AuthZ). They sound similar, get abbreviated together as "auth," and share HTTP headers — but confusing them is one of the most common ways teams ship vulnerabilities. A valid JWT proves identity; it does not, by itself, prove that identity may delete someone else's invoice. This guide separates AuthN from AuthZ, walks through RBAC and attribute-based models, shows where each runs in the request path, and covers the OAuth patterns that blur the line when scopes are misread as permissions.

The core distinction

Authentication establishes identity — binding a request to a principal (user account, service account, API key owner, wallet address). You authenticate with credentials: passwords, one-time codes, hardware keys, signed tokens, or cryptographic wallet signatures.

Authorization evaluates whether that authenticated principal may perform a specific action on a specific resource. "Alice is logged in" is authentication. "Alice may edit document 42 but not document 99" is authorization.

The order matters. Authorization without authentication is meaningless — you cannot decide what "anonymous" may do without a policy for unauthenticated users. Authentication without authorization is dangerous — proving you are Alice does not mean every endpoint should trust you equally.

A concrete analogy

At an airport, showing your passport at check-in is authentication: the airline verifies you are the person named on the ticket. Boarding a particular flight in a particular seat is authorization: your ticket class and gate assignment determine access, not merely your identity. A forged passport fails AuthN; a valid passport for a different flight fails AuthZ.

Authentication in practice

Modern AuthN stacks combine something you know (password), something you have (phone, security key), and something you are (biometrics). Production systems rarely stop at a single factor for sensitive accounts.

Common authentication mechanisms

  • Session cookies — server stores session state; browser sends an opaque session ID. AuthN succeeds when the session is valid and unexpired.
  • Bearer tokens (JWT, opaque tokens) — client presents a token; server validates signature, expiry, and issuer. The token carries identity claims but should not be the sole AuthZ layer.
  • API keys — long-lived secrets identifying a project or integration. Treat keys as AuthN for machines; scope them tightly for AuthZ.
  • Passkeys / WebAuthn — phishing-resistant public-key credentials bound to an origin. See our passkeys guide for ceremony details.
  • Mutual TLS — client certificates authenticate service-to-service callers inside a mesh or private network.
  • Wallet signatures — in Web3 flows, a signed message proves control of a keypair without a traditional account password.

What authentication outputs

After successful AuthN, your middleware should attach a stable principal identifier to the request context: user_id, sub (subject claim), service_account, or wallet_pubkey. Downstream code reads that context; it should not re-parse credentials in every handler. Failed AuthN returns 401 Unauthorized — "we do not know who you are" or "your credentials are invalid/expired."

Authorization in practice

Authorization is a policy decision: given principal P, action A, and resource R, allow or deny. Policies can live in application code, a dedicated policy engine (OPA, Cedar, SpiceDB), database ACL tables, or cloud IAM bindings.

Authorization models

  • ACL (access control lists) — each resource lists which principals may access it. Simple for small datasets; painful at scale.
  • RBAC (role-based access control) — users hold roles (editor, billing_admin); roles map to permissions. Easy to audit; role explosion is the main risk.
  • ABAC (attribute-based access control) — policies evaluate attributes: department, clearance level, resource owner, time of day, IP geography. Flexible; harder to reason about without tooling.
  • ReBAC (relationship-based) — permissions derive from graph relationships ("editors of folder X may edit documents inside X"). Popular in collaboration products (Google Zanzibar model).

Most products layer models: RBAC for coarse admin boundaries, ReBAC or ABAC for per-object sharing. A user with the member role might authenticate successfully yet lack permission to export another team's data — that is AuthZ doing its job.

Failed authorization

When the caller is known but not permitted, return 403 Forbidden — not 401. Returning 401 invites credential-stuffing retries; 403 signals "we know who you are, and the answer is no." For existence-leaking endpoints (e.g. "does user 555 exist?"), some APIs return 404 instead of 403 to avoid confirming resource presence — a product decision, not a HTTP purist rule.

Where teams confuse AuthN and AuthZ

JWT claims are not a permission system

Stuffing "role": "admin" into a JWT payload and trusting it client-side is authorization theater. Anyone who obtains a token sees the claims; attackers who steal tokens inherit embedded roles. Signatures prove the issuer wrote the claims — not that the issuer should have granted them. Prefer short-lived access tokens, server-side permission lookups, or centrally issued tokens with explicit scope validation at each service.

OAuth scopes vs application permissions

OAuth scopes (read:orders, openid profile) are consent boundaries between a user, an authorization server, and a client application. They are not a substitute for your API's internal AuthZ matrix. A mobile app may hold read:profile while your backend still checks row-level ownership before returning another user's PII.

Authenticated does not mean trusted

Session fixation, stolen cookies, and CSRF exploit authenticated browsers to perform unauthorized actions. AuthN succeeded; AuthZ failed because the action was not initiated by the legitimate user. Sensitive mutations need anti-CSRF tokens, SameSite cookies, or re-authentication (step-up AuthN) in addition to role checks.

API gateways vs services

An API gateway often terminates TLS and validates JWTs (AuthN). Individual microservices must still enforce AuthZ — defense in depth. Never assume "passed the gateway" equals "may call any internal endpoint."

The request lifecycle

A well-structured HTTP pipeline separates concerns:

  1. Transport security — TLS terminates; optional mTLS for service mesh.
  2. Authentication middleware — extract credential, validate, attach principal to context. On failure: 401, stop.
  3. Authorization middleware or policy check — evaluate (principal, action, resource). On failure: 403, stop.
  4. Business logic — runs only after both gates pass.
  5. Audit log — record principal, action, resource, decision, correlation ID.

Default to fail closed: missing policy means deny. Explicit allow rules for public routes (GET /health, marketing pages) rather than implicit open access that developers forget to close. Integration tests should include negative cases — authenticated users attempting forbidden actions — not only happy paths.

Least privilege and delegation

Authorization design should grant the minimum permissions required for a task. Temporary elevation ("sudo mode" for 15 minutes) beats permanent admin roles. Service accounts for batch jobs get scoped credentials rotated automatically — see secrets management for storage and rotation patterns.

Delegation (user A grants app B limited access to resource R) combines AuthN (B proves identity to the authorization server) with AuthZ (user A's consent record and token scopes). Revocation must propagate: deleting a role or consent should invalidate outstanding tokens within your TTL budget or via explicit token revocation lists.

Production checklist

  1. Document AuthN mechanisms per surface (web session, mobile token, API key, webhook HMAC).
  2. Return 401 for bad/missing credentials; 403 for valid identity denied by policy.
  3. Enforce AuthZ in the service that owns the data — not only at the edge.
  4. Avoid long-lived tokens with embedded admin claims; prefer server-side permission lookups.
  5. Map roles/permissions in one auditable source; version policy changes.
  6. Test negative authorization paths in CI (user A cannot access user B's resource).
  7. Log allow/deny decisions with principal ID and resource ID; never log secrets.
  8. Require step-up AuthN for destructive actions (password change, payout, key export).
  9. Review OAuth scopes quarterly; remove unused consent grants.
  10. Run tabletop exercises: stolen session token — what can attacker actually do?

Key takeaways

  • AuthN proves identity; AuthZ grants permission — different questions, different HTTP status codes.
  • Order matters — authenticate first, then authorize every sensitive action.
  • Tokens prove who signed in — not automatically what they may do.
  • Layer models — RBAC for coarse roles, ABAC/ReBAC for fine-grained sharing.
  • Fail closed — deny by default; audit explicit allows.

Related reading