Authentication and Authorization

A place for notes on identity and access control.

Overview

Authentication: Who are you? Authorization: What are you allowed to do?

Key concepts

1. Session Vs. Token Authentication

Session

  • Server maintains state (Redis, DB, etc.)
  • Client holds a reference (e.g. session ID in cookie)

Token

  • Client holds a credential, typically Authorization: Bearer in header. Sometimes seen in cookie as well.
  • Presents it when accessing resources
  • Opaque/random tokens or JWT
    • Opaque tokens: does not expose claims directly; typically requires server-side lookup or introspection (e.g. API key)
    • JWT: a self-contained token containing claims that can typically be verified without a server-side lookup.

Both session and token authentication can exist in the same system. The choice depends on the use case and system design.

2. JWT (One Way of Token Authentication)

JWT appears in format of {Header}.{Payload}.{Signature}

{ // decoded Header
  "alg": "HS256",
  "typ": "JWT"
}
{ // decoded Payload
  "iss": "auth.example.com",    // issuer
  "sub": "user123", // subject
  "aud": "payment-service", // audience
  "exp": 1790000000,    //  expiration time
  "iat": 1789999000,    // issued at
  "nbf": 1789999000,    // not before
  "jti": "abc123"   // jwt id
}

The signature is generated from the encoded header and payload using a cryptographic signing algorithm, such as HS512 or RS512.

  • HS512: uses a shared secret to generate and verify the signature
  • RS512: uses a private key to sign and a public key to verify

The signature ensures the integrity and authenticity of the header and payload.

Cookie is a browser-managed way of storing small pieces of data and automatically sending them with matching HTTP requests.

  • Secure in cookie means browser only sends cookie over HTTPS. It protects the cookie value being transported over plaintext HTTP.
  • HttpOnly in cookie prevents Javacript (Frontend/Browser side uses document.cookie) to retrieve the cookie, but it still allows browser to send the cookie in request header.
  • refresh_token and access_token are also commonly seen in cookies. access_token appears quite commonly as JWT token. It is short-lived (about 15 minutes, depending on how authentication serves). refresh_token is usually valid for days that are longer than access_token can live. This is because access_token is meant to live short for safety purpose, but we don’t want our user to login every 15 minutes. Hence, once access_token is expired, client can retrieve a new access_token with a not-yet-expired refresh_token to client.
  • SameSite controls whether the browser sends a cookie with cross-site requests, helping protect against CSRF attacks.

4. Browser Security

CSRF (Cross-Site Request Forgery)

  • Tricks an authenticated user’s browser into sending an unwanted request to another site.
  • Possible because browsers automatically attach matching cookies to requests.
  • SameSite cookies can help mitigate CSRF.

Same-Site vs. Cross-Site

  • Site is roughly defined by scheme + registrable domain.
  • https://web1.example.com → https://web2.example.com is same-site.
  • Mainly relevant to cookie policies such as SameSite.

Same-Origin vs. Cross-Origin

  • Origin = scheme + hostname + port.
  • https://web1.example.com → https://web2.example.com is cross-origin.
  • Mainly relevant to browser Same-Origin Policy and CORS.

CORS (Cross-Origin Resource Sharing)

  • Controls whether browser JavaScript from one origin is allowed to access resources/responses from another origin.
  • The server specifies allowed origins using headers such as Access-Control-Allow-Origin.
  • Enforced by browsers; clients such as curl, Postman, and server-to-server requests are not subject to browser CORS restrictions.
  • Some cross-origin requests trigger an OPTIONS preflight request before the actual request.

5. RBAC (Role-Based Access Control) & Resource-Level Authorization

RBAC

  • Permissions are assigned to roles, and roles are assigned to users
  • A role represents a set of allowd actions, e.g. ADMIN, OPERATOR, VIEWER
  • Permissions can be expressed as resource:action, such as client:read, client:update, or invoice:void
  • Commonly enforced through backend middleware or authorization policies

Resource-Level Authorization

  • Having permission to perform an action does not necessarily mean the user can perform it on every resource
  • Authorization may also depend on resource ownership, tenant membership or other relationships
  • Example: A user with document:read permission my only access documents belonging to their organiaztion

Security Considerations

  • Least Privilege: Grant only the minimum permissions necessary
  • Deny by Default: Reject access unless explicitly permitted
  • Backend Enforcement: Never rely on frontend visibility or disabled buttons for authorization
  • BOLA (Broken Object Level authorization): A vulnerability where an API fails to verify whether a user is authorized to access a specific object, often by manipulating resource IDs.

6. OAuth 2.0

OAuth 2.0 is an authorization framework that allows an application to obtain limited access* to protected resources, often on behalf of a user, **without requiring the user’s password.

Resource Owner: Entity that owns the control of access (user)
Client: The application that request to access the resource (third-party application)
Authroization Server: Responsible for assigning token (OAuth server)
Resource Server: The server that responsible for the proteected resource (e.g. Google Calendar API)

Real Example Flow

sequenceDiagram
    autonumber
    actor User
    participant Client as Client App
    participant Auth as Authorization Server
    participant API as Resource Server

    User->>Client: Connect Google Calendar
    Client-->>User: Redirect to /authorize
    User->>Auth: Authorization Request (via browser)
    Auth->>User: Login and Consent
    User->>Auth: Approve Access
    Auth-->>User: Redirect with Authorization Code
    User->>Client: Authorization Code + State
    Client->>Auth: Exchange Code + PKCE Verifier
    Auth-->>Client: Access Token (+ Refresh Token)
    Client->>API: Request with Access Token
    API-->>Client: Protected Resource
    Client-->>User: Display Calendar Events

Authorization Code: a short-lived, temporary grant for client to exchange for Access Token; it is also possible to get captured
PKCE: is responsible to prevent attacker from redeeming token with captured Authorization Code. Client generates a code_verifier – SHA-256 + Base64URL –> code_challenge. This code challenge is transmitted at /authorize step. Client will pass code_verifier to auth server at token exchange stage
Scope: Defines the permissions requested by the Client, such as calendar.read. The granted scopes limit what the Client can access with the Access Token
State: Binds the authorization response to the original request and can help prevent CSRF attacks
Access Token: A credential used by the Client to access protected resources. It can be an opaque token or a JWT

7. OIDC (OpenID Connect)

OIDC is an authentication protocol built on top of OAuth 2.0. It allows clients to verify the identity of an end user and obtain basic profile information.

On top of OAuth 2.0, Authorization Request should include openid scope. When exchanging auth code for Token, ID Token should also be returned.

OpenID Provider (OP): Authorization Server that supports OIDC (e.g. Google, Okta)
Relying Party (RP): The application relying on OP for user identity authentication
ID Token: A signed JWT issued by the OP, containing claims about the authenticated user
Subject (sub): Identifies the authenticated user within the Issuer. RP typically uses (iss, sub) to identify an external user
ID Token Validation

  • Verify signature using the OP’s trusted public keys (JWKS)
  • Validate issuer (iss)
  • Validate audience (aud)
  • Validate expiration (exp)
  • Validate nonce if one was sent in the authentication request

RP trusts the verified authentication result from OP, rather than authenticating the user directly

sequenceDiagram
    autonumber
    actor User
    participant Client as Client App (Relying Party)
    participant OP as OpenID Provider (Google)

    User->>Client: Sign in with Google
    Client-->>User: Redirect to /authorize
    User->>OP: scope=openid profile email + PKCE
    OP->>User: Login / Consent if needed
    User->>OP: Authenticate / Approve
    OP-->>User: Redirect with Authorization Code
    User->>Client: Authorization Code + State
    Client->>OP: /token (code + code_verifier)
    OP-->>Client: ID Token + Access Token
    Note over Client: Validate ID Token
    Note over Client: Identify user by iss + sub
    Client-->>User: Create application session

SSO (Single Sign-On): Multiple applications can reuse an existing authentication session at the same Identity Provider. Each application performs its own OIDC flow and may create its own local session after validating the ID Token. Applications do not need to share ID Tokens or sessions.

Interview Questions

  1. What is the difference between authentication and authorization? When would you return 401 vs. 403?

  2. How does JWT authentication work? How does the server verify a JWT, and what are the security considerations?

  3. What are the differences between session-based authentication and stateless JWT authentication? What are their trade-offs?

  4. How would you securely handle authentication tokens in a browser? What do HttpOnly, Secure, and SameSite protect against?

  5. What is CSRF, and how is it different from CORS?

  6. How would you implement RBAC and resource-level authorization in a backend API? How do you prevent users from accessing resources they do not own?

  7. What problem does OAuth 2.0 solve? How does Authorization Code Flow work, and why is PKCE needed?

  8. What is the difference between OAuth 2.0 and OIDC? How does a Relying Party verify an ID Token?

References

Add links to documentation and further reading.