I have a web service providing a variety of features to logged in users, running Java Spring Boot. I am adding a new feature that requires this web service to communicate with an external resource server, accessing resources specific to the logged in user. The resource server is using OAuth2. Google drive for purposes of this question, but I will need to integrate multiple clients for different resource servers.
I am trying to get an authorization_code
flow to work with an Oauth2 clent and Spring Security and I don’t understand how to make it work because it doesn’t seem to be able to link requests with my authenticated users.
My understanding is, the flow should be
- A user authenticated to my service tries to access a Google Drive resource
- My service redirects the user to Google’s Oauth2 flow
- User gives permission, Google’s server redirect back to
GOOGLE_AUTH_CALLBACK
URL that I configured with a code and state - Spring security should now process the redirect, take the code and state, convert them into access and refresh tokens, and store those in authorized client repository linked to the user.
It’s the last step that is failing – OAuth2AuthorizationCodeGrantFilter
stores the data under anonymousUser
instead of the logged in user
My client configuration is
security:
oauth2:
client:
registration:
google:
client-id: <SECRET>
client-secret: <SECRET?
authorization-grant-type: authorization_code
redirect-uri: http://... // same as GOOGLE_AUTH_CALLBACK constant in code
scope: https://www.googleapis.com/auth/drive
provider:
google:
authorization-uri: https://accounts.google.com/o/oauth2/auth
token-uri: https://accounts.google.com/o/oauth2/token
My security configuration is
auth
.requestMatchers(GOOGLE_AUTH_CALLBACK)
.permitAll()
.anyRequest()
.authenticated();
I can make the initial call to my service, it redirects to Google, Google’s flow works and redirects back to GOOGLE_AUTH_CALLBACK
url value. When Google’s flow redirects back to my service, the bearer token header that my web service is using for authentication is no longer there. I had to declare GOOGLE_AUTH_CALLBACK
as not requiring authentication in the configuration above.
Now, the callback comes in, the Oauth2AuthorizationCodeGrantFilter
picks it up, finds the original request, resolves it and gets to this point in the code Spring security GitHub Source
String principalName = (currentAuthentication != null) ? currentAuthentication.getName() : "anonymousUser";
In my setup currentAuthentication
turns out to be null and therefore the tokens aren’t stored as associated with the current user.
It seems I am missing something about how the system should work – how can the callback request coming from Google’s server be authenticated and linked to the user who issued the original request, before the series of redirects?
I’m assuming that there’s some setup that is possible to preserve the user principal through those redirects but I cannot figure out what may be missing in my system.
Myroslava Dzikovska is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.