Authentication & Authorization

By Pritesh Yadav 11 min read

Almost every security system rests on two questions, asked in order. First: who are you? Second: what are you allowed to do? The first is authentication (often shortened to AuthN) — proving an identity. The second is authorization (AuthZ) — deciding what that proven identity may access. These are two distinct steps, and confusing them is one of the most common — and most expensive — sources of security bugs. This section walks from proving identity, through modern passwordless login, into how systems decide what each user can touch.

Identity
The claimed and verified set of attributes about an entity — a user, a service, or a device (for example "this is account alice@acme.com, an admin in the Finance department").
Authentication (AuthN)
The act of proving an identity is genuinely who it claims to be.
Authorization (AuthZ)
The act of granting or denying a specific action to an already-authenticated identity.
Analogy: Authentication is showing your passport at the airport — proving you are who you say. Authorization is whether your boarding pass lets you into the first-class lounge. The passport tells the guard who you are; the boarding pass tells them what you may do. You always authenticate first, then authorize each action.

  Request --> [ AuthN: who are you? ] --pass--> [ AuthZ: may you do X? ]
                    |                                   |
                  fail                                fail
                    v                                   v
              401 Unauthorized                    403 Forbidden

4.1 Authentication factors

Proof of identity comes from factors, grouped into three classic categories:

  • Something you KNOW — a password, PIN, or security question. A shared secret in your head.
  • Something you HAVE — a phone, a hardware key (like a YubiKey), a smartcard, or an authenticator app generating TOTP codes (Time-based One-Time Passwords — the rotating 6-digit numbers).
  • Something you ARE — biometrics: fingerprint, face, or iris.

Two extra categories are sometimes added: somewhere you are (geolocation) and something you do (behavioral patterns like typing rhythm). MFA (Multi-Factor Authentication, or 2FA for exactly two) means requiring proof from two or more different categories.

Common mistake: Two passwords are NOT MFA — they are both "something you know." Real MFA crosses categories, e.g. a password (know) plus a phone tap (have). The whole point is that an attacker who steals one category still lacks the other.

4.2 Passwords: why they are weak

Passwords are a shared secret the server must store, and humans handle them badly: they reuse one password everywhere (so one breach enables credential stuffing — replaying stolen logins across many sites), pick guessable ones, and fall for phishing. The data is damning. IBM's Cost of a Data Breach 2025 found the global average breach cost fell to $4.44M, but the US hit a record $10.22M. Phishing overtook stolen credentials as the #1 initial attack vector (16% of breaches), while breaches using stolen/compromised credentials took the longest to detect and contain — an average of 292 days.

Modern password policy (NIST SP 800-63B Rev. 4)

NIST's 2024/2025 guidance reversed decades of bad advice:

  • Minimum 8 characters (15 if the password is the only factor); support at least 64; allow all printable and Unicode characters, including spaces.
  • Do NOT force periodic rotation — no 60/90-day expiry. Forced changes just produce Password1 → Password2. Require a change only on evidence of compromise.
  • Drop composition rules (no mandatory "1 uppercase + 1 symbol").
  • Screen new passwords against breach blocklists (e.g. HaveIBeenPwned).
  • Allow paste — it helps password managers.

Password storage done right

Never store plaintext, never a plain fast hash (MD5/SHA-256 — GPUs crack billions per second), and never encrypt (that's reversible). Use a slow, memory-hard password hashing function with a unique random salt per password (random data mixed in, stored alongside the hash, defeating precomputed "rainbow tables"). OWASP currently recommends Argon2id (min 19 MiB memory, 2 iterations). Acceptable alternatives: bcrypt (work factor ≥10, 72-byte input limit) or PBKDF2 (for FIPS environments). Optionally add a pepper — a secret HMAC key kept out of the database. Use a reputable library; never hand-roll this.

4.3 MFA: strong, but not bulletproof

MFA dramatically reduces account takeover, but attackers adapt. Factors form a strength hierarchy:

  weaker  SMS OTP  <  TOTP app  <  push approval  <  FIDO2/passkey  stronger
          (SIM-swap)   (AiTM)       (fatigue)        (phishing-resistant)
  • SIM swapping — attacker ports your phone number to their SIM, intercepting SMS codes (eSIM provisioning can do this in minutes).
  • MFA fatigue / push bombing — spamming approval prompts until the tired user taps "approve." The 2025 Verizon DBIR ties this to roughly 14% of incidents.
  • Adversary-in-the-Middle (AiTM) — a fake login page relays your password AND your OTP to the real site in real time, defeating TOTP and push. Phishing-as-a-service kits like Tycoon 2FA and EvilProxy industrialize this.
Example: The FBI/CISA-tracked group Scattered Spider chained SIM swaps, push fatigue, and help-desk social engineering to break into major firms. The lesson: legacy MFA reduces phishing risk but doesn't eliminate it — which is why the industry is moving to phishing-resistant auth.

4.4 Passkeys, WebAuthn, and FIDO2 (the 2025 trend)

The clearest direction of travel is passwordless login built on public-key cryptography. WebAuthn (a W3C browser API) plus CTAP (the device protocol) together make up FIDO2. At registration your device generates a key pair; the private key never leaves the device (sealed in a secure enclave or TPM), and the server stores only the public key. Logging in means signing a server-issued challenge, unlocked by your biometric or PIN.

Why it is phishing-resistant: the credential is cryptographically bound to the site's origin (its domain), so a fake site can't trigger it; there is no shared secret to steal, phish, or breach. "Synced passkeys" roam across your devices via Apple/Google/Microsoft/1Password clouds; "device-bound" passkeys (hardware keys) stay put.

Key takeaway: 2025 numbers from the FIDO Alliance: 69% of users have at least one passkey, over 1 billion people have activated one, and 48% of the top-100 sites support them. Google reports passkey sign-ins succeed ~4x more often than passwords (~93% vs ~63%). Passkeys are where authentication is heading.

4.5 Sessions vs tokens, and cookie flags

Once authenticated, the server must remember you across requests. Two approaches:

AspectStateful SessionStateless Token (JWT)
Where state livesOn the server; client holds an opaque session IDInside the token itself (the claims)
Each requestServer looks up the sessionServer only verifies the signature
RevocationEasy — delete server-sideHard — valid until it expires
ScalingNeeds a shared session storeGreat for APIs/microservices

A common hybrid: a short-lived access token (5–15 min) plus a long-lived refresh token that rotates on each use. Store the refresh token in an HttpOnly cookie; keep the access token in memory.

Cookie security flags are the seatbelts here: HttpOnly stops JavaScript from reading the cookie (blunting theft via XSS); Secure sends it only over HTTPS; SameSite (Strict / Lax / None) controls cross-site sending and is the primary defense against CSRF (Cross-Site Request Forgery). In 2025 browsers block third-party cookies and enforce SameSite by default.

4.6 OAuth 2.0 vs OpenID Connect, SSO, and SAML

OAuth 2.0 is an authorization framework, not a login protocol. It lets an app get delegated access to your resources without your password ("let this app read your Google Drive files"). Roles: resource owner (you), client (the app), authorization server, and resource server; access is granted via scopes. Use the Authorization Code flow with PKCE for web, mobile, and single-page apps.

OpenID Connect (OIDC) is a thin identity layer on top of OAuth 2.0. It adds an ID Token (a JWT with verified identity claims like sub and email) so the app knows who logged in. OIDC powers "Sign in with Google/Apple."

Best practice: Mnemonic — "OAuth = a valet key (access); OIDC = an ID card (who you are)." Using bare OAuth for login is a classic, dangerous mistake: it grants access but never verifies identity.

SSO (Single Sign-On) means logging in once to reach many apps — a user experience built on a federation protocol. SAML 2.0 is the older XML-based enterprise standard (an Identity Provider like Okta or Entra sends signed XML assertions to a Service Provider). Rule of thumb: SAML for legacy enterprise SSO, OIDC for new or consumer apps.

4.7 JWTs: structure and pitfalls

A JWT (JSON Web Token) has three base64url parts: header.payload.signature. The header names the algorithm, the payload holds claims, and the signature covers the first two. Base64 is not encryption — anyone can read the payload, so never put secrets in it.

  • alg:none — the spec allows an "unsigned" token; a careless library lets an attacker strip the signature and forge admin:true. Fix: a server-side algorithm allowlist (e.g. only RS256); reject none.
  • alg confusion (RS256→HS256) — attacker signs using the public key as if it were the HMAC secret.
  • Weak HMAC secret — brute-forced; use a ≥256-bit random secret.
  • No/long expiry — always set a short exp, and validate exp, nbf, iat, iss, aud, jti.
  • Storing JWTs in localStorage — XSS-stealable; prefer HttpOnly cookies.
Common mistake: Believing "stateless means no revocation needed." A leaked JWT stays valid until it expires unless you maintain a denylist. Keep lifetimes short.

4.8 Authorization models

ModelDecides access by…Strength / weakness
RBAC (Role-Based)roles assigned to users (admin/editor/viewer)Simple, ubiquitous; "role explosion," no row-level rules
ABAC (Attribute-Based)attributes of user/resource/environmentFlexible ("manager in Finance, work hours"); hard to audit
ReBAC (Relationship-Based)relationships between entitiesPowerful ("view a doc if you can view its folder"); a superset
PBAC (Policy-Based)centralized policies outside app codeAuditable, reusable (OPA, Cedar); extra infrastructure
Example: Google's Zanzibar (USENIX 2019) is a global ReBAC system using object#relation@user tuples — over 2 trillion of them, ~10M requests/sec, p95 under 10ms. It inspired OpenFGA, SpiceDB, and Auth0 FGA. Modern apps increasingly move authorization into a dedicated service instead of scattering if-checks through the code.

4.9 Least privilege and Zero Trust

The principle of least privilege grants the minimum access needed, for the shortest time — shrinking the "blast radius" if an account is compromised. It pairs with just-in-time access and regular access reviews (orphaned accounts are a top breach vector).

Zero Trust (NIST SP 800-207) means "never trust, always verify." It abolishes implicit trust based on network location — "inside the firewall" is meaningless. Every request is authenticated, authorized, and encrypted per session, evaluated on signals like user identity, device health, and behavior. A Policy Decision Point (PDP) decides; a Policy Enforcement Point (PEP) enforces — replacing the old "castle-and-moat" perimeter model.

4.10 The #1 mistake: Broken Access Control

Broken Access Control is #1 (A01) in the OWASP Top 10:2025 — essentially every tested app had some form of it. The canonical case is IDOR / BOLA (Insecure Direct Object Reference / Broken Object Level Authorization): an app fetches an object by a user-controllable ID without checking ownership. Change GET /api/orders/12345 to 12346 and you read someone else's order. The root cause is authorization checks done client-side, forgotten on an endpoint, or relying on "they can't see the link" (security by obscurity).

Example (Snowflake, 2024): Around 165 organizations were breached because attackers reused infostealer-harvested credentials to log into tenant accounts with no MFA enforced — a pure authentication-hygiene failure that pushed Snowflake to make MFA mandatory.

Common mistakes

  • Confusing AuthN with AuthZ — proving identity but never checking permission per action.
  • Using OAuth for login without OIDC, so identity is never actually verified.
  • Trusting JWT claims without validating signature, algorithm, and expiry.
  • Shipping 2010-era password rules (forced rotation, composition) NIST now warns against.
  • No MFA on privileged or admin accounts.
  • Relying on unguessable IDs alone instead of a real ownership/tenant check.

Best practices

  • Enforce authorization on every request, server-side, deny-by-default.
  • Check ownership and tenant scope on every object lookup.
  • Hash passwords with Argon2id (or bcrypt/PBKDF2) and screen against breach lists.
  • Roll out phishing-resistant passkeys/FIDO2; require MFA on all privileged accounts.
  • Use short-lived access tokens with rotating refresh tokens in HttpOnly+Secure+SameSite cookies.
  • Centralize authorization (PBAC/ReBAC) rather than scattering ad-hoc checks.
  • Apply least privilege with just-in-time access and routine de-provisioning.
Key takeaway: Authentication and authorization are separate steps — prove who you are, then check what you may do — and most real breaches exploit a gap in one or the other: stolen credentials with no MFA, or a missing ownership check (IDOR). The modern playbook is phishing-resistant passkeys for AuthN, properly hashed passwords as a fallback, validated short-lived tokens for sessions, and centralized, deny-by-default, least-privilege authorization checked on every single request.

Continue reading