π Attackers are smarter. π Browsers are stricter. π Users expect zero compromise.
In 2025, if your OAuth login isn't CSRF-proof, session-safe, and device-aware, you're one breach away from disaster.
This blog shows you how to go beyond "default" Spring Security and implement high-security OAuth using CSRF tokens, session ID binding, and device metadata validation.
π‘οΈ 1. CSRF Protection in OAuth Flows
Without CSRF protection, an attacker can trick your user into unknowingly authorizing an app.
Spring Security already supports CSRF β but let's make it explicit in OAuth:
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.oauth2Login(Customizer.withDefaults())
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
return http.build();
}
}β Here:
- CSRF tokens are stored in HttpOnly cookies.
- Every OAuth request is bound to the CSRF token.
π 2. Session ID Binding (Stop Session Hijacking)
If an attacker steals a session cookie, they can impersonate the user. The trick? Tie the OAuth session ID to user metadata (IP, user-agent, etc).
@Component
public class SessionValidationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
String storedUA = (String) session.getAttribute("USER_AGENT");
String currentUA = request.getHeader("User-Agent");
if (storedUA != null && !storedUA.equals(currentUA)) {
session.invalidate(); // π¨ Possible hijack detected
} else {
session.setAttribute("USER_AGENT", currentUA);
}
}
filterChain.doFilter(request, response);
}
}xβ This ensures:
- A stolen cookie from another device won't work.
- Session hijacking attempts are stopped cold.
π± 3. Device Metadata Fingerprinting
Beyond session binding, you can fingerprint devices (OS, browser, geolocation). Each OAuth login can be checked against stored device metadata.
@Entity
public class DeviceMetadata {
@Id @GeneratedValue
private Long id;
private String username;
private String deviceId;
private String userAgent;
private String ipAddress;
private LocalDateTime lastLogin;
}On login:
@Component
public class OAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
String username = authentication.getName();
String ua = request.getHeader("User-Agent");
String ip = request.getRemoteAddr();
// Save metadata
DeviceMetadata device = new DeviceMetadata();
device.setUsername(username);
device.setUserAgent(ua);
device.setIpAddress(ip);
device.setLastLogin(LocalDateTime.now());
// π¨ Extra: If IP/UA is unusual, trigger MFA
}
}β This way, you can:
- Detect new device logins.
- Enforce MFA when device fingerprint changes.
- Alert users on suspicious login activity.
π₯ Real-World Security Stack
- CSRF Tokens β Block request forgery
- Session Binding β Stop cookie replay/hijacking
- Device Metadata β Detect unusual/suspicious logins
- MFA + Refresh Token Rotation β Final lock against takeover
With these 3 layers, your Spring Boot OAuth is ready for real-world threats.
A message from our Founder
Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community.
Did you know that our team run these publications as a volunteer effort to over 3.5m monthly readers? We don't receive any funding, we do this to support the community. β€οΈ
If you want to show some love, please take a moment to follow me on LinkedIn, TikTok, Instagram. You can also subscribe to our weekly newsletter.
And before you go, don't forget to clap and follow the writerοΈ!