Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Access token with one refresh token

I have multiple mobile clients and they all authenticate using the password grant flow. For this, I just want to use one very long lasting refresh token with multiple shorter-lived access tokens. I have been trying to generate multiple access tokens with Password Grant in spring, however, anytime I refresh my access token the old access token stops working. I checked the database and there is only one record in the oauth_access_token table at all times for that specific authentication. Isn't Spring Oauth2 supposed to generate multiple access tokens for one refresh token? Thank you for the help.

like image 948
BlackLog Avatar asked Mar 04 '23 00:03

BlackLog


2 Answers

It is supported by OAuth2 specification, see RFC 6749:

1.5. Refresh Token

Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain a new access token when the current access token becomes invalid or expires, or to obtain additional access tokens with identical or narrower scope (access tokens may have a shorter lifetime and fewer permissions than authorized by the resource owner).

But Spring Security OAuth2 doesn't support it, see DefaultTokenServices#refreshAccessToken:

  // clear out any access tokens already associated with the refresh
  // token.
  tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);

and TokenStore#removeAccessTokenUsingRefreshToken:

Remove an access token using a refresh token. This functionality is necessary so refresh tokens can't be used to create an unlimited number of access tokens.

One work-around is to implement a custom TokenStore.

like image 131
dur Avatar answered Mar 27 '23 08:03

dur


The goal here is to make it possible for multiple devices to work with different tokens independently of one another. It turned out that in Spring OAuth we cannot have one refresh token with multiple access tokens associated with it. It also turned out that it was not necessary to have such a configuration; as long as we can have separate authentications for separate devices, that would suffice. Now, a key is generated(DefaultAuthenticationKeyGenerator) based on client_id, scope, and username. As I am not using the scope, I simple put the device info in the scope and got the following:

{
"access_token": "32e11a1b-cb9f-4317-95b0-e850f260d160",
"token_type": "bearer",
"refresh_token": "d097e4ea-a9d9-4e0c-94cd-7c15e1c8e690",
"expires_in": 3599,
"scope": "android2",
"exp": 1557843628674
}

To make this happen, just leave out the scope configuration as follows:

  public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {

configurer
    .inMemory()
    .withClient(CLIENT_ID)
    .secret(passwordEncoder.encode(CLIENT_SECRET))
    .authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
    // ************* Comment this out ******
    //.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
    .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
    refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
    }

Using this method, each and every device can get a separate token. Also, when the user logs out, we have the option of logging him out of all his devices. However, we cannot leave out the scope in our requests; the scope parameter must always be sent in refresh token requests.

like image 25
BlackLog Avatar answered Mar 27 '23 07:03

BlackLog