How to Implement JWT Authentication from Scratch in Spring Security
Fast recall
Quick revision
Core answer
Authorization: Bearer ..., a token util for generation/validation, and a `SecurityFilterChain` with `SessionCreationPolicy.STATELESS`, CSRF disabled, and the filter registered before `UsernamePasswordAuthenticationFilter`. The signed token lets the server verify authenticity without a per-request DB hit. For most apps that only validate tokens (not issue them), use Spring's OAuth2 Resource Server (spring-boot-starter-oauth2-resource-server) instead — zero custom filter code, JWKS rotation, and standardized claims handling.Hands-on knowledge of stateless authentication — can the candidate wire up a complete JWT flow without scaffolding?
Storing JWTs in localStorage without understanding XSS risk, or forgetting to set SessionCreationPolicy.STATELESS, causing sessions to be created unnecessarily.
Discuss token expiry, refresh token strategy, signing algorithms (HS256 vs RS256), and token revocation challenges.
Interview-ready guide
Interview answer
The filter implementation
- Extend
OncePerRequestFilter - Extract
Authorization: Bearerheader - Validate JWT: signature,
exp,alg,iss,aud - Build
UsernamePasswordAuthenticationToken(sub, null, authorities) SecurityContextHolder.getContext().setAuthentication(auth)- Register:
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
Token storage
HttpOnlycookie: JS-inaccessible, XSS-safe, needs CSRF protection if cookie-basedlocalStorage: XSS-vulnerable, any script reads and exfiltrates- For SPAs: short-lived access token in memory + long-lived refresh in
HttpOnlycookie
Refresh token rotation
- Access token 15min TTL; client refreshes silently
- Refresh token 7 days; on use, issue new + revoke old
- Reuse of revoked refresh token signals theft -> revoke entire family
SecurityFilterChain settings
csrf.disable()— safe withAuthorizationheaderSessionCreationPolicy.STATELESS— no phantom sessionsaddFilterBefore— JWT filter before UsernamePassword filter
Best alternative for non-issuers
spring-boot-starter-oauth2-resource-server+oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))spring.security.oauth2.resourceserver.jwt.issuer-uri: https://...- JWKS rotation handled automatically
Common security mistakes
- Catching JWT exceptions in filter -> security bypass
- Long-lived access tokens -> revocation impossible
- Trusting
algfrom token header -> algorithm confusion - Putting PII in claims -> data exposure
How to Implement JWT Authentication from Scratch in Spring Security
Direct Answer
JWT auth in Spring Security needs three things: a OncePerRequestFilter that extracts and validates the JWT from Authorization: Bearer ..., a token util for generation/validation, and a SecurityFilterChain with SessionCreationPolicy.STATELESS, CSRF disabled, and the filter registered before UsernamePasswordAuthenticationFilter. The signed token lets the server verify authenticity without a per-request DB hit. For most apps that only validate tokens (not issue them), use Spring's OAuth2 Resource Server (spring-boot-starter-oauth2-resource-server) instead — zero custom filter code, JWKS rotation, and standardized claims handling.
Common Mistakes & Pitfalls
Storing JWTs in localStorage without understanding XSS risk, or forgetting to set SessionCreationPolicy.STATELESS, causing sessions to be created unnecessarily.
Check your understanding
Answer these without looking back at the article.
- How would you implement token refresh without forcing the user to log in again?
- What are the security implications of HS256 vs RS256 signing, and when would you choose each?
- How do you handle JWT revocation if a user logs out or their account is compromised?
- When should you use Spring's OAuth2 Resource Server instead of a custom filter?
Related interview prep categories
2Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.