← Home
🏗Crack System Design with DSA AnimatorSystem DesignNEW
🏗 System Design›Networking & Realtime

🔐Authentication & Authorization

Authenticate identity first, then authorize actions with explicit and auditable policy.

📌 Key IdeaAuthentication verifies who the caller is; authorization decides what the caller is allowed to do. Design both as separate stages with clear policy, correct 401/403 behavior, and auditability.
📖

Definition

Authentication answers who is calling (JWT, API key, session, mTLS). Authorization answers what they can do (scopes, roles, attributes, ownership checks).

✨

Why It Matters

  • Prevents confused security design where identity and permission checks get mixed.
  • Reduces privilege-escalation bugs by enforcing least-privilege decisions explicitly.
  • Makes incidents easier to debug with consistent deny reasons and audit logs.
✅

When to Use

  • Any API where caller identity and permission boundaries matter.
  • Multi-tenant systems with role/scope-based access control.
  • Teams that need consistent 401/403 semantics and audit trails.
🚫

When NOT to Use

  • Pure internal scripts/tools where auth context is not applicable.
  • Assuming role/scope alone can replace ownership/business-rule checks.
💻

Code Variations

1️⃣ Gateway filter pipeline sketchjava
public Decision handle(Request req) {
  String token = extractBearer(req);
  Claims claims = jwtVerifier.verify(token); // signature, exp, iss, aud

  PolicyInput in = new PolicyInput(
      req.method(), req.path(), claims.subject(),
      claims.scopes(), claims.tenantId()
  );

  if (!policyEngine.allow(in)) return Decision.forbidden("missing_scope");

  req.headers().put("X-Principal-Id", claims.subject()); // gateway-generated
  req.headers().put("X-Tenant-Id", claims.tenantId());
  return Decision.allow(req);
}
Core rule remains universal: 401 for invalid identity, 403 for denied permission.
2️⃣ Route policy map (coarse-grained)json
{
  "routes": [
    { "method": "GET", "path": "/orders/**", "anyOfScopes": ["orders:read"] },
    { "method": "POST", "path": "/orders/**", "anyOfScopes": ["orders:write"] },
    { "method": "GET", "path": "/admin/**", "allOfScopes": ["admin:read", "tenant:internal"] }
  ]
}
Keep policies explicit and versioned; avoid hidden hard-coded checks.
3️⃣ Request lifecycle contract to servicestext
External headers -> sanitize
Authenticate -> Authorize -> inject trusted identity headers
Forward to service

Service still performs:
- ownership checks (user can access this order?)
- business constraints (state transitions, limits)
Defense-in-depth: authn/authz at edge + domain checks at service.
📊

Authentication vs Authorization

AspectAuthenticationAuthorization
Core questionWho is the caller?Can this caller perform this action?
Typical inputJWT/API key/mTLS cert/session tokenClaims, scopes, roles, tenant, route/method
Failure status401 Unauthorized403 Forbidden
OutputTrusted identity contextAllow/deny decision + policy reason
🔀

Common Confusions Cleared Up

Edge checks and domain checks are both required

Auth at edge is valuable, but domain-level checks (resource ownership, business constraints) must still be validated in the service handling that domain.

Token validation and policy evaluation are separate stages

First verify token signature/expiry/audience/issuer. Then evaluate policy from claims and request context. Mixing these concerns creates brittle and unsafe logic.

Never trust caller-provided identity headers

Only trust headers that your gateway injects after successful auth. Strip inbound spoofable identity headers from external requests.

🧪

Variations / Implementations

JWT bearer token flow (most common)

Verify JWT (signature + exp + iss + aud), build principal, then evaluate policy from claims + request context.

mTLS service-to-service edge

Mutual TLS authenticates service identity; authorization policy maps cert/service account to allowed actions.

External policy engine (OPA/Cedar-style)

Authorization decision is delegated to policy engine for centralized updates and traceable allow/deny rules.

⚠️

Common Mistakes / Anti-Patterns

  • Returning 403 for invalid/expired token (should be 401).
  • Forwarding all token claims blindly to downstream services.
  • Using only role names without action-level scopes (too coarse over time).
  • No clock-skew tolerance for token validation, causing random auth failures.
  • No audit trail for deny decisions (hard to debug incidents).
🎤

Interview Q&A

🔮

Likely Follow-up Questions

  • How do you revoke JWT before expiry (blacklist, short TTL + refresh token)?
  • How do you rotate signing keys (kid, JWKS cache, rollout strategy)?
  • How do you model tenant isolation in policy and downstream queries?
  • What gateway metrics show auth problems early (401 rate, 403 rate, policy latency)?
🧾

Quick Cheat Sheet

AuthnIdentity proof (JWT/API key/mTLS).
AuthzPermission decision from policy + context.
Status code401 invalid/missing identity, 403 identity valid but not allowed.
BoundaryEdge = coarse checks; service = fine-grained domain checks.
🔗

Related Topics