Securing Spring Boot APIs with OAuth2 and JWT: A Practical Guide
· Samir Gautam
Most "secure" Spring Boot APIs I get called in to fix aren't actually broken — they're just built on a security model nobody fully understood. Here's the pattern I use by default, and why each piece is there.
Why OAuth2 + JWT, not sessions
Session-based auth is fine for a single monolith. The moment you have more than one service — a mobile app, a partner API, a background worker — shared session state becomes a coordination problem. A signed JWT carries its own proof of identity, so any service can verify a request without calling back to a central session store.
The shape of it
- Authorization Server issues short-lived access tokens (I default to 15 minutes) and longer-lived refresh tokens.
- Resource Server (your Spring Boot API) validates the JWT signature and scopes on every request — no database lookup needed for auth itself.
- Spring Security's
OAuth2ResourceServerConfigurerdoes most of the heavy lifting once you point it at your issuer's JWK set.
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin")
.anyRequest().authenticated())
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
Three mistakes I see repeatedly
- Long-lived access tokens. If a token leaks, its lifetime is your exposure window. Keep access tokens short and lean on refresh tokens for longevity.
- Trusting the JWT payload without checking
audandiss. A valid signature only proves who issued the token — not that it was issued for your API. - No token revocation story. Short expiry buys you most of what you need, but for anything handling payments I also keep a denylist of revoked token IDs in Redis, checked on the hot path.
Where this earns its keep
I built this exact pattern for a fintech client's payment gateway — OAuth2 + JWT securing every transaction endpoint, with idempotent request handling on top so a retried request never double-charges a customer. Getting the auth layer right up front meant the security audit six months later was a formality, not a scramble.
If you're stitching together auth for a Spring Boot service and want a second pair of eyes on the design before you ship it, that's exactly the kind of review I do.