keycloakgoogle-oauthgoogle-authenticationgoogle-openid

Keycloak only gets Google refresh token on first login


I'm using Keycloak with Google as identity provider. I need a refresh token from Google in order to manage the calendar of users. Here are my Keycloak Google IDP settings:

Keycloak Google IDP settings

After login I fetch the refresh token according to https://www.keycloak.org/docs/latest/server_development/index.html#retrieving-external-idp-tokens. Which looks like this:

{
    "access_token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "expires_in": 3599,
    "refresh_expires_in": 0,
    "refresh_token": "YYYYYYYYYYYYYYYYYYYYYYYYYYYY",
    "token_type": "Bearer",
    "id_token": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
    "not-before-policy": 0,
    "scope": "openid https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile",
    "accessTokenExpiration": 1593706596
}

Now the problem is when I login a second time and then try to fetch the refresh token again it's gone:

{
    "access_token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "expires_in": 3599,
    "refresh_expires_in": 0,
    "token_type": "Bearer",
    "id_token": "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
    "not-before-policy": 0,
    "scope": "https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid",
    "accessTokenExpiration": 1593706782
}

I'm really not sure how this is possible. One thing that came to my mind is that Keycloak is not respecting the "Request refresh token" setting on subsequest logins, but I don't know how to verify this.


Solution

  • It's not a Keycloak bug, it's a Google specification. The refresh_token is only provided on the first authorization from the user. Here the documentation of this behavior:

    refresh_token: A token that you can use to obtain a new access token. Refresh tokens are valid until the user revokes access. Again, this field is only present in this response if you set the access_type parameter to offline in the initial request to Google's authorization server. - source

    If you want to get the refresh token again you must:

    1. Go to the page showing Apps with access to your account: https://myaccount.google.com/u/0/permissions.
    2. Under the Third-party apps menu, choose your app.
    3. Click Remove access and then click Ok to confirm
    4. The next OAuth2 request you make will return a refresh_token (providing that it also includes the 'access_type=offline' query parameter.

    related to this answer