Search code examples
springspring-securityoauth-2.0spring-security-oauth2spring-oauth2

Spring OAuth2 server cannot refresh token with Resource owner credentials (password) grant flow


I have configured an OAuth2 authorisation server with spring security oauth, using jwt tokens:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

...
    @Override
    public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
    }

    @Bean
    public ApprovalStore approvalStore() {
        return new JdbcApprovalStore(dataSource);
    }

    @Bean
    public TokenStore tokenStore() {
        var jwtTokenStore = new JwtTokenStore(tokenConverter());
        jwtTokenStore.setApprovalStore(approvalStore());
        return jwtTokenStore;
    }

    @Bean
    public JwtAccessTokenConverter tokenConverter() {
        var converter = new JwtAccessTokenConverter();
        var keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(jwtKeyStore), jwtKeyPass.toCharArray());
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwtkey"));
        return converter;
    }

}

There is a client that has password and refresh_token grants. I can get access and refresh tokens with the following request:

curl --request POST \
   --url 'http://localhost:8080/oauth/token?grant_type=password&scope=read' \
  --header 'authorization: Basic <xxxxxxx>' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'username=xxxxxxx&password=xxxxxxx'

Response:

{
    "access_token": "<long access token>",
    "token_type": "bearer",
    "refresh_token": "<long refresh token>",
    "expires_in": 599,
    "scope": "read",
    "subject": "xxx",
    "jti": "xxx"
}

However, when I try to refresh the token, I get an error Invalid refresh token. Further debugging into Spring codes I see that on the first request, it doesn't insert a row into oauth_approvals table. And on the second request (refreshing the token) it thinks that the user has not approved the scope (although I have autoapprove=true).

This is not the case with implicit or authorization_code grant flow: in those cases it does insert a row into oauth_approvals table, and the token is refreshed successfully.

Is this a bug in Spring OAuth or is there any workaround?


Solution

  • After digging more into Spring's codes, I came to conclusion that this is indeed a bug there. So I extended JdbcApprovalStore and used that one instead. Here is pseudo-code

    public class JdbcApprovalStoreAutoApprove extends JdbcApprovalStore {
        ...
        @Override
        public List<Approval> getApprovals(String userName, String clientId) {
            if (client has auto approved scopes) {
                return those scopes;
            }
            return super.getApprovals(userName, clientId);
        }