๐ด The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [authorization_request_not_found] ClientRegistration not found with identifier: google
at org.springframework.security.oauth2.client.web.HttpSessionOAuth2AuthorizationRequestRepository.loadAuthorizationRequest(HttpSessionOAuth2AuthorizationRequestRepository.java:100)โก Quick Fix Works 80% of the time
Ensure your reverse proxy passes the correct headers, or use a cookie-based AuthorizationRequestRepository.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.oauth2Login(Customizer.withDefaults());
// If behind Nginx, ensure proxy_set_header X-Forwarded-Proto $scheme; is set
return http.build();
}๐ง Why this Happens
Tap to expand the deep technical explanation
When a user clicks 'Login with Google', Spring Security generates an authorization request and saves it in the HTTP session. It then redirects the user to Google. When Google redirects back to your app, Spring looks for that saved request to verify the state. If it's missing (due to session expiration, blocked cookies, or domain mismatch), it throws this error.
The HITEC City Parking Spot Analogy:
It's like leaving a coat at a coat check. You get a ticket. When you come back to claim it, the attendant says, 'I don't see any record of this coat.' If you lose the ticket (cookie/session), or the attendant shifts, you can't prove you left it there.
๐ How to Reproduce Confirm this is your error
Start an OAuth2 login flow. When redirected to Google, clear your browser cookies for your local app. Complete the Google login. When the callback hits your app, it will fail.
๐ ๏ธ Solutions (5 Ways to Fix)
Fix Reverse Proxy Headers (Nginx/Traefik)
๐ Use this if your app works locally but fails in production behind a load balancer.
Spring Security stores the OAuth2 state in the session, which is tied to the domain/protocol. If the proxy terminates SSL but doesn't tell Spring, Spring might generate HTTP URLs for the callback, breaking the state.
# Nginx configuration
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme; # CRITICAL FOR OAUTH2
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}Use a Cookie-based Repository
๐ Use this if your sessions are failing due to distributed environments or strict firewalls.
Instead of storing the state in the server session, store it in a short-lived cookie in the user's browser.
import org.springframework.security.oauth2.client.web.CookieOAuth2AuthorizationRequestRepository;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authRequestRepo) throws Exception {
http.oauth2Login(oauth -> oauth
.authorizationEndpoint(auth -> auth
.authorizationRequestRepository(authRequestRepo) // Wire the cookie-based repo
)
);
return http.build();
}
@Bean
public OAuth2AuthorizationRequestRepository<OAuth2AuthorizationRequest> authRequestRepository() {
return new CookieOAuth2AuthorizationRequestRepository(); // Cookie-based, not session-based
}Ensure browser cookies aren't blocked
๐ Use this if testing in a strict corporate environment or old browser.
If the user's browser blocks third-party cookies or SameSite=Strict cookies, the session cookie is lost during the redirect to Google and back.
// Ensure Spring Session cookie is set to SameSite=Lax
// (Usually default in Spring Boot, but check your server.servlet.session.cookie.same-site property)Fix Server Clock / Time Sync
๐ Use this if servers are randomly losing state.
If your server clock is out of sync, the session or cookie might expire instantly because it thinks the timestamp is in the past.
# Sync server time
sudo ntpdate ntp.ubuntu.comCheck server.servlet.context-path
๐ Use this if your app runs under a sub-path (e.g., /api).
The OAuth2 callback URL must exactly match the path registered in Google Console. If the context path is missing, the state mismatch occurs.
# application.properties
server.servlet.context-path=/api
# Google Console Redirect URI: https://localhost:8080/api/login/oauth2/code/google๐ Version Notes
Uses HttpSessionOAuth2AuthorizationRequestRepository by default.
Identical default, but better logging for reverse proxy misconfigurations.
๐ก๏ธ How to Prevent This Next Time
Always use `X-Forwarded-Proto` in reverse proxies. Use cookie-based OAuth2 state storage for microservices architectures.