For my Spring Boot 2.4 application, I've configured OAuth2 Login (OpenID Connect) that uses the OAuth 2.0 Authorization Code Grant flow internally.
The OAuth 2.0 specification for this flow defines the state
parameter as recommended, mostly for CSRF-protection issues. A sample request looks like the following:
https://authorization-server.com/oauth/authorize
?client_id=a17c21ed
&response_type=code
&state=5ca75bd30
&redirect_uri=https%3A%2F%2Fexample-app.com%2Fauth
&scope=photos
As the application should run with multiple instances (at least two), I'm running into issues as this state
parameter is randomly generated with different values for each Spring Boot instance. So the callback has to arrive at the same instance the request was initiated, as otherwise, the validation of this state
field fails.
The relevant Spring Security code part I found is the following (resolve
method of DefaultOAuth2AuthorizationRequestResolver
)
builder.clientId(clientRegistration.getClientId())
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
.redirectUri(redirectUriStr)
.scopes(clientRegistration.getScopes())
.state(this.stateGenerator.generateKey()) // this line generates it
.attributes(attributes);
If I enable sticky sessions on the load balancer, everything works as expected. But then I wouldn't describe the application setup as fully stateless.
Is there are way to persist the used state
parameter e.g. in a database to share it among several Spring Boot instances to verify the callback at every instance? Or do I have to manually provide a custom StringKeyGenerator
and somehow tweak the state
validation?