Auth Patterns
BothAuthentication
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) andtyp: "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
stateparameter 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 ascode_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
@PreAuthorizewith 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
@PostAuthorizeto 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 = :currentTenantto every query via Hibernate filters - Database-level: PostgreSQL RLS policies enforce rules transparently
- Spring Data JPA: use
@Filter/@FilterDefor 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
Authorizationheader or custom header, never in query parameters (logged by proxies) - Set expiry dates and monitor usage for anomalies
Common Vulnerabilities (OWASP)
LightVulnerabilities
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
PreparedStatementor JPA/Hibernate named parameters — never string concatenation - ORMs mitigate most injection, but native queries and
@Querywith 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:textnotth: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 CSRFSameSite=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@RequestBodywith 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 RequestswithRetry-Afterheader - 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
LightCrypto
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
BCryptPasswordEncoderis 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.Macin Java or Spring'sHmacUtils - Common use: verifying Stripe/GitHub webhook payloads by computing HMAC of request body
Recommended Resources
- OWASP Top 10 (2021) — The definitive list of critical web application security risks. Read at least the summaries.
- OWASP Cheat Sheet Series — Concise, actionable guidance for every major security topic. Excellent interview prep.
- Spring Security Reference Documentation — Official docs covering authentication, authorization, OAuth2, CSRF, CORS, and filter chains.
- Baeldung — Spring Security Tutorials — Practical tutorials with code examples for JWT, OAuth2, method security, and more.
- jwt.io — Interactive JWT debugger and library directory. Paste a token to inspect claims instantly.
- OWASP Authentication Cheat Sheet — Best practices for login flows, password policies, MFA, and session management.