Auth Patterns

Both
Interview tip: Be ready to whiteboard a complete auth flow end-to-end — from login to token issuance to API authorization. Interviewers probe whether you understand the full chain, not just individual pieces.

Authentication

JWT Structure (header.payload.sig)

A JSON Web Token has three Base64url-encoded parts separated by dots: the header (algorithm + type), the payload (claims), and the signature that prevents tampering.

  • Header declares alg (e.g. HS256, RS256) and typ: "JWT"
  • Payload carries registered claims (iss, exp, sub) plus custom claims
  • Signature = HMAC or RSA over base64(header).base64(payload)
  • JWTs are not encrypted by default — anyone can decode the payload
  • Keep tokens short-lived; avoid storing sensitive data in claims

JWT vs Session Cookie Tradeoffs

Sessions store state on the server and send an opaque ID via cookie; JWTs are self-contained and stateless but harder to revoke.

  • Sessions: easy revocation (delete server-side), require sticky sessions or shared store
  • JWTs: horizontally scalable (no server state), but revocation requires a blocklist
  • Cookies get automatic CSRF protection via SameSite; JWTs in localStorage are XSS-vulnerable
  • Hybrid approach: short-lived JWT access token + server-side refresh token

OAuth2 Flows (code, implicit, client credentials)

OAuth2 defines multiple grant types for different use cases. The authorization code flow is the most secure for user-facing apps; client credentials suits service-to-service.

  • Authorization Code: redirects user to auth server, returns code exchanged for token server-side
  • Implicit: token returned directly in URL fragment — deprecated due to token exposure
  • Client Credentials: machine-to-machine, no user involvement
  • Resource Owner Password: user gives credentials directly — avoid unless legacy
  • Always use HTTPS; validate state parameter to prevent CSRF

PKCE Flow

Proof Key for Code Exchange adds a code challenge/verifier to the authorization code flow, preventing interception attacks on public clients (SPAs, mobile apps).

  • Client generates random code_verifier, sends SHA-256 hash as code_challenge
  • Auth server verifies the original verifier when exchanging the code for a token
  • Eliminates need for a client secret in public clients
  • Now recommended for all OAuth2 authorization code flows, not just public clients

Refresh Token Rotation

Each time a refresh token is used, the server issues a new refresh token and invalidates the old one. This limits the window of abuse if a token is stolen.

  • Detects reuse: if an old refresh token is presented, revoke the entire token family
  • Store refresh tokens server-side (DB or Redis) with a family/lineage ID
  • Set absolute expiry on refresh tokens (e.g. 7-30 days) independent of rotation
  • Combine with short-lived access tokens (5-15 min) for defense in depth

Token Revocation Strategies

JWTs cannot be invalidated natively since they are self-contained. Revocation requires additional server-side mechanisms.

  • Blocklist/Denylist: store revoked JTI in Redis with TTL matching token expiry
  • Token versioning: store a per-user version; reject tokens with older version
  • Short expiry + refresh: rely on natural expiration; revoke only the refresh token
  • For critical systems, consider opaque tokens validated via introspection endpoint

Authorization

RBAC vs ABAC

Role-Based Access Control assigns permissions to roles; Attribute-Based Access Control evaluates policies against user/resource/environment attributes at runtime.

  • RBAC: simple, fits most apps — ROLE_ADMIN, ROLE_USER
  • ABAC: flexible for complex rules — "allow if user.department == resource.department AND time is business hours"
  • RBAC is easier to audit; ABAC scales better for fine-grained requirements
  • Spring Security supports both via @PreAuthorize with SpEL expressions

@PreAuthorize with SpEL

Spring Security's @PreAuthorize annotation evaluates a SpEL expression before method execution, enabling declarative method-level authorization.

  • @PreAuthorize("hasRole('ADMIN')") — basic role check
  • @PreAuthorize("#userId == authentication.principal.id") — parameter-level ownership check
  • Combine with @PostAuthorize to filter return values
  • Enable with @EnableMethodSecurity (replaces deprecated @EnableGlobalMethodSecurity)
  • Keep expressions simple; extract complex logic into a custom PermissionEvaluator

Row-Level Security Patterns

Restrict data access so users can only see rows they own or have been granted access to — critical for multi-tenant applications.

  • Application-level: add WHERE tenant_id = :currentTenant to every query via Hibernate filters
  • Database-level: PostgreSQL RLS policies enforce rules transparently
  • Spring Data JPA: use @Filter / @FilterDef or custom repository base class
  • Always enforce at the DB layer as a safety net even if the app layer also filters

API Key Management

API keys are simple bearer credentials for service-to-service auth. They lack user context and must be treated as secrets.

  • Hash keys before storage (like passwords) — store only the hash, return key once on creation
  • Scope keys to specific permissions; support key rotation without downtime
  • Transmit via Authorization header or custom header, never in query parameters (logged by proxies)
  • Set expiry dates and monitor usage for anomalies

Common Vulnerabilities (OWASP)

Light
Interview tip: You will rarely be asked to exploit vulnerabilities, but you must articulate the threat model and the mitigation. "We use parameterized queries" is the bare minimum — explain why string concatenation is dangerous.

Vulnerabilities

SQL Injection & Parameterized Queries

SQL injection occurs when untrusted input is concatenated into SQL statements. Parameterized queries (prepared statements) separate code from data, neutralizing the attack.

  • Use PreparedStatement or JPA/Hibernate named parameters — never string concatenation
  • ORMs mitigate most injection, but native queries and @Query with SpEL still need care
  • Second-order injection: data stored safely, then used unsafely in a later query
  • Defense in depth: least-privilege DB user, input validation, WAF rules

XSS — Stored vs Reflected

Cross-Site Scripting injects malicious scripts into pages viewed by other users. Stored XSS persists in the database; reflected XSS comes from the request itself.

  • Stored: attacker saves script in DB (e.g. comment field) — executes for every viewer
  • Reflected: malicious payload in URL parameter, echoed back in response
  • DOM-based: client-side JS reads untrusted data and writes to DOM unsafely
  • Mitigations: output encoding, Content Security Policy (CSP) headers, sanitize HTML input
  • Spring: Thymeleaf auto-escapes by default; use th:text not th:utext

CSRF — SameSite Cookies

Cross-Site Request Forgery tricks a logged-in user's browser into sending unwanted requests. SameSite cookie attribute is the modern primary defense.

  • SameSite=Lax: cookies sent on top-level navigations only — blocks most CSRF
  • SameSite=Strict: cookies never sent on cross-origin requests
  • Spring Security enables CSRF tokens by default for session-based apps
  • Stateless JWT APIs typically disable CSRF (no cookies = no CSRF risk)
  • Double-submit cookie pattern as fallback for older browsers

IDOR (Insecure Direct Object Reference)

IDOR lets an attacker access another user's data by manipulating an identifier (e.g. changing /orders/123 to /orders/124) when authorization checks are missing.

  • Always verify the authenticated user owns or has access to the requested resource
  • Use UUIDs instead of sequential IDs to make guessing harder (but still enforce authz)
  • Implement authorization at the service/repository layer, not just the controller
  • Automated testing: parameterize IDs in integration tests with different user contexts

Mass Assignment

Mass assignment occurs when an API blindly binds request body fields to entity properties, allowing attackers to set fields like isAdmin or price that should be server-controlled.

  • Use dedicated DTOs/request objects — never bind directly to JPA entities
  • Whitelist allowed fields explicitly; reject unknown fields
  • Spring: @JsonIgnoreProperties(ignoreUnknown = true) on DTOs, avoid @RequestBody with entity classes
  • Jackson: @JsonProperty(access = READ_ONLY) for computed/server-set fields

Rate Limiting as Security Control

Rate limiting caps how many requests a client can make in a time window, defending against brute-force attacks, credential stuffing, and denial-of-service.

  • Apply at API gateway (e.g. Spring Cloud Gateway, Nginx) for global protection
  • Algorithms: fixed window, sliding window, token bucket, leaky bucket
  • Return 429 Too Many Requests with Retry-After header
  • Tighter limits on auth endpoints (login, password reset) vs general APIs
  • Combine with account lockout policies for brute-force defense

Secret Management (Vault, AWS Secrets Manager)

Secrets (DB passwords, API keys, encryption keys) should never be hardcoded or stored in source control. Use a dedicated secret manager with access policies and audit logging.

  • HashiCorp Vault: dynamic secrets, lease-based rotation, fine-grained ACL
  • AWS Secrets Manager: auto-rotation for RDS, Lambda integration, versioning
  • Spring Cloud Vault or Spring Cloud AWS for transparent secret injection
  • Rotate secrets regularly; detect leaked secrets via git hooks (e.g. truffleHog, git-secrets)
  • 12-factor app: inject via environment variables, not config files in the image

Encryption & Crypto Basics

Light
Interview tip: You are not expected to implement crypto algorithms, but you must know when to use hashing vs encryption vs encoding and why. The TLS handshake is a popular system design warm-up question.

Crypto

Symmetric vs Asymmetric Encryption

Symmetric encryption uses one shared key for encrypt/decrypt (fast, used for bulk data). Asymmetric uses a key pair — public to encrypt, private to decrypt (used for key exchange and signatures).

  • Symmetric: AES-256 is the standard; key distribution is the hard problem
  • Asymmetric: RSA, ECDSA; slower but solves key exchange
  • TLS uses asymmetric to exchange a symmetric session key, then switches to symmetric
  • JWTs: HS256 = symmetric HMAC, RS256 = asymmetric RSA signature

TLS Handshake (Conceptual)

TLS establishes an encrypted channel between client and server. The handshake negotiates cipher suites, authenticates the server via certificate, and derives session keys.

  • ClientHello: supported TLS versions, cipher suites, random nonce
  • ServerHello: chosen cipher suite, server certificate, random nonce
  • Client verifies certificate chain against trusted CAs
  • Key exchange (e.g. ECDHE) produces a shared pre-master secret
  • Both sides derive symmetric session keys; all further traffic is encrypted

mTLS in Microservices

Mutual TLS requires both client and server to present certificates, providing two-way authentication. Essential for zero-trust service mesh architectures.

  • Each service has its own certificate issued by an internal CA
  • Service meshes (Istio, Linkerd) automate mTLS with sidecar proxies
  • Eliminates need for service-to-service API keys or tokens within the mesh
  • Certificate rotation and short-lived certs (e.g. SPIFFE/SPIRE) reduce blast radius

Hashing vs Encryption vs Encoding

These three are commonly confused. Hashing is one-way (passwords), encryption is two-way with a key (secrets), encoding is reversible without a key (data format conversion).

  • Hashing: SHA-256, bcrypt — irreversible, used for integrity checks and password storage
  • Encryption: AES, RSA — reversible with correct key, used for confidentiality
  • Encoding: Base64, URL encoding — not security, just format transformation
  • Common mistake: Base64-encoding a password and calling it "encrypted"
  • Interview cue: "How would you store passwords?" — answer is always hashing, never encryption

bcrypt for Password Storage

bcrypt is an adaptive password hashing function with a built-in salt and configurable cost factor, making brute-force attacks computationally expensive.

  • Spring Security's BCryptPasswordEncoder is the default password encoder
  • Cost factor (work factor) of 10-12 is typical; increase as hardware gets faster
  • Salt is embedded in the hash output — no separate salt column needed
  • Alternatives: Argon2 (memory-hard, newer), scrypt (memory-hard)
  • Never use MD5 or SHA-256 alone for passwords — too fast, no salt by default

HMAC for Message Integrity

Hash-based Message Authentication Code combines a secret key with a hash function to verify both integrity and authenticity of a message.

  • HMAC-SHA256: used in JWT signatures (HS256), webhook verification, API signing
  • Unlike plain hashing, requires the secret key — prevents tampering by third parties
  • Constant-time comparison is critical to prevent timing attacks
  • Use javax.crypto.Mac in Java or Spring's HmacUtils
  • Common use: verifying Stripe/GitHub webhook payloads by computing HMAC of request body

Recommended Resources