Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refresh_token flow issues while using external identity providers only #7

Open
ArthurasJ opened this issue Feb 18, 2016 · 7 comments
Open

Comments

@ArthurasJ
Copy link

I have used an example of auth-server to write my own authorization server (only slight changes that should not make difference) that uses external identity providers and issues its own access tokens (JWT, but I don't think that matters in this case). When the access token expires, Spring Oauth2 client tries to refresh access token by using refresh_token flow that is enabled in authorization server. In the DefaultTokenServices class there is method refreshAccessToken which apart from refreshing token also tries to re-authenticate user using authenticationManager. And it causes a problem because as I said, my authorization server uses only external identity providers and therefore authorizationManager can't reauthenticate user. Am I missing something?

@dsyer
Copy link
Collaborator

dsyer commented Feb 18, 2016

I believe you do need to check user accounts are still valid on refresh (the app will work if you don't but it's not doing a very good job of identity mamagement, is it?). To do that actually requires a UserDetailsService (not an AuthenticationManager) so we should think about whether the sample needs one of those for this use case. My guess is "yes", and it should be implemented using the same user info endpoint if it is available (or token info if not). Probably this will be a Spring Boot feature initially since UserInfoTokenServices is defined there, but maybe we could work on an implementation here and see if it works?

@ArthurasJ
Copy link
Author

If I understand you correctly, it should be enough to implement a class (lets say CustomUserDetailsService) that implements UserDetailsService and just pass it to AuthorizationServerEndpointsConfigurer?

@dsyer
Copy link
Collaborator

dsyer commented Feb 18, 2016

Yes. That's the correct API I believe.

@ArthurasJ
Copy link
Author

Good. UserDetailsService is an interface that has one method loadUserByUsername(String username). If I use more than one external providers there will be more than one user info endpoints. How do I determine which one endpoint to call if in method loadUserByUsername(String username) I have only one parameter - username? Also to call user info endpoint of external identity provider the access token is needed - how to get that one at CustomUserDetailsService?

I'm quite new to Spring Security/Oauth, so not everything is clear to me.

@dsyer
Copy link
Collaborator

dsyer commented Feb 18, 2016

If there is only one provider (the vanilla use case in this tutorial) it's easy - you just inject an OAuth2RestOperations into your UserDetailsService and use it to probe the user info API (it will have an access token, or it redirect to the provider so it can get one).

If there are multiple providers I guess we need to work a bit harder. Then, you were right the first time, we need a full AuthenticationManager. The custom AM can assume that the incoming Authentication is the user's full Authentication, which will include details of the provider (e.g. the Map of user details originally obtained from the remote service). This extension point is not available at the same level of convenience as the UserDetailsService extension point - you actually have to create a complete DefaultTokenServices (the one that we use to manage our own tokens, not the remote ones), inject your AM into that, and then inject it into the AuthorizationServerEndpointsConfigurer instead of just injecting the UDS.

@ArthurasJ
Copy link
Author

The custom AM can assume that the incoming Authentication is the user's full Authentication, which will include details of the provider (e.g. the Map of user details originally obtained from the remote service).

I am not sure about this part. While refreshing token, to my custom AuthenticationManager method authenticate(Authentication authentication) (that is located in DefaultTokenServices) comes user instance of class PreAuthenticatedAuthenticationToken. How do I put essential info about provider in this object? I have tried overriding DefaultAccessTokenConverter method convertAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication). But for example, with facebook in the OAuth2Authentication authentication object there is no info about provider. Any ideas, how to get that info?

@dsyer
Copy link
Collaborator

dsyer commented Feb 22, 2016

The PreAuthenticatedAuthenticationToken will have a principal which is an Authentication and in that will be details which are the original data extracted from the user info endpoint. In the case of facebook, for instance, I can see an entry like link=https://www.facebook.com/app_scoped_user_id/.... There will almost certainly be other signatures for other providers. Once you have identified the provider you can locate the corresponding OAuth2RestOperations and use it to ping back the same endpoint and verify that the user account is still valid, according to the provider.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants