Search code examples
authenticationoauth-2.0jwtkeycloak

Keycloak does not refresh the token


I'm trying to refresh a token but Keycloak returns a 400 Bad Request error with following message:

{
    "error": "invalid_grant",
    "error_description": "Invalid refresh token"
}

I successfully get the refresh token in a request like this:

curl --location --request POST 'http://localhost:8080/auth/realms/my_realm/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=my_user' \
--data-urlencode 'password=my_password' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=my_client_id' \
--data-urlencode 'client_secret=my_client_secret'

So I get a JWT response with access token and refresh token. Both of them appear to be valid as I load them in jwt.io.

But when I try to use the refresh token I get previous error. The request is like this:

curl --location --request POST 'http://localhost:8080/auth/realms/my_realm/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=my_client_id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=my_refresh_token' \
--data-urlencode 'client_secret=my_client_secret'

In Keycloak's log there is no clue of what the problem is.

Waht could be the cause? Or at least, is there a way to get more info on the cause of the error from Keycloak' response or log?

EDIT:

I have implemented an User Storage Provider SPI so it does the authentication against an external DB but it doesn't manage users into Keycloak. Is it needed that the token owner user exists in Keycloak so refreshing the token works?

Thanks.


Solution

  • Finally it was an issue in my User Storage Provider SPI. It was necessary to implement following method as Keycloak takes the user ID from the refresh token and look for the user by such ID:

    public UserModel getUserById(String id, RealmModel realm) {
        StorageId storageId = new StorageId(id);
        String username = storageId.getExternalId();
        return getUserByUsername(username, realm);
    }