We're using resource-owner credentials grant type (with oauth2:password
in security-config.xml
. Let's play out this scenario to explain my predicament:
ROLE_USER
TokenStore
, keyed on his username
, client_id
, and scope
. (see DefaultAuthenticationKeyGenerator.java)authority
of ROLE_MOBILE_USER
.ROLE_MOBLE_USER
added to his user in the database.DefaultTokenServices
returns him the same, non-working access token.authority
is to wait until his old access token expires so he can get a new access token with the correct authority
.There are a number of ways to address this.
For one, the administration app that adds ROLE_MOBILE_USER
to Bob's authorities could then clear all access tokens and authorizations in the database. This way the DefaultTokenServices
will just create a new one with the correct authorities serialized as his new OAuth2Authentication. However we may not want the Administration webapp to be concerned with OAuth at this point (at least not yet). If possible we'd like to keep the administration app concerns as concise as possible, and right now there are no dependencies on oauth.
We could expose the DELETE
method to the /oauth/access_token
endpoint and tell the mobile app to try deleting that access token and re-requesting one, just in case the stored authorities
are stale. This feels more like a work-around though.
Finally I can serialize the authorities
in my own defined AuthenticationKeyGenerator
. It would basically use the username
, client_id
, scope
, and authorities
of the authorization and perform the same digest algorithm on them. This way when Bob tries to log in he'll get the same access token, but the underlying token store will recognize that he has a different authentication (from the authentication manager in the token granter bean) and refresh its database. The problem I have with this solution is that it simply relies on the implementation behavior of the underlying token store (though both InMemoryTokenStore
and JdbcTokenStore
behave this way).
Can you think of any better/cleaner solutions? Am I over-thinking this?
Thanks in advance.
To refresh your access token as well as an ID token, you send a token request with a grant_type of refresh_token . Be sure to include the openid scope when you want to refresh the ID token. If the refresh token is valid, then you get back a new access and the refresh token.
The Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired. This allows clients to continue to have a valid access token without further interaction with the user.
A refresh token can help you balance security with usability. Since refresh tokens are typically longer-lived, you can use them to request new access tokens after the shorter-lived access tokens expire.
OAuth2 is an authorization framework that enables the application Web Security to access the resources from the client. To build an OAuth2 application, we need to focus on the Grant Type (Authorization code), Client ID and Client secret.
I resolved this issue in my app by deleting all tokens for a given user when the authentication information is sent.
Use a custom AuthenticationProvider bean.
@Component("authenticationProvider")
public class AuthenticationProviderImpl implements AuthenticationProvider
Autowire in the token store bean.
@Autowired
@Qualifier("tokenStore")
private TokenStore tokenStore;
Then in the authenticate method, remove all tokens for a given user if the credentials are passed a second time.
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
try {
//Do authentication
//Delete previous tokens
Collection<OAuth2AccessToken> tokenCollection = tokenStore.findTokensByUserName(token.getName());
for (OAuth2AccessToken oToken : tokenCollection){
tokenStore.removeAccessToken(oToken);
}
//return Authentication;
}
}
Most of the requests will be using a token and will bypass this entirely, but when the credentials are passed, a new token will be generated. This token will be associated with the new authentication object which will include all new roles, and changes made to the user.
I had the same problem and I solved it with this function:
protected void reloadUserFromSecurityContext(SecurityContext securityContext, Person user){
OAuth2Authentication requestingUser = (OAuth2Authentication) securityContext.getUserPrincipal();
Object principal = (PersonUserDetails) requestingUser.getUserAuthentication().getPrincipal();
if(principal instanceof PersonUserDetails) {
((PersonUserDetails) principal).setPerson(user);
}
OAuth2AuthenticationDetails authDetails = (OAuth2AuthenticationDetails) requestingUser.getDetails();
OAuth2AccessToken tokenStored = jdbcTokenStore.readAccessToken(authDetails.getTokenValue());
jdbcTokenStore.storeAccessToken(tokenStored, requestingUser);
}
That is a example for update an attribute for PersonUserDetails object that is in OAuth2Authentication
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With