Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Negative refresh token expiration (exp timestamp in the past) #11990

Closed
alexwais opened this issue May 14, 2022 · 4 comments · Fixed by #17525
Closed

Negative refresh token expiration (exp timestamp in the past) #11990

alexwais opened this issue May 14, 2022 · 4 comments · Fixed by #17525
Assignees
Labels
area/oidc Indicates an issue on OIDC area kind/bug Categorizes a PR related to a bug team/rh-iam
Milestone

Comments

@alexwais
Copy link

alexwais commented May 14, 2022

Describe the bug

I came across a strage behavior (seemingly a bug) regarding the refresh token expiration.

Under some (unknown) circumstances, the refresh_token issued by Keycloak contains an exp claim timestamp that is before the iat timestamp, e.g.:

  "exp": 1652513276,
  "iat": 1652529209,

This happens when retrieving an access token + refresh token from the https://kc-host/realms/my-realm/protocol/openid-connect/token endpoint using the authorization_code grant type.

Likewise, the response from the token endpoint contains a negative refresh_expires_in value:

{
   "access_token": "eyJhbGciOiJ...",
   "expires_in": 300,
   "refresh_expires_in": -15933,
   "refresh_token": "eyJhbGciOiJ...",
   "token_type": "Bearer",
   "id_token":" eyJhbGciOiJ...",
   "not-before-policy": 0,
   "session_state": "fa8347b3-4717-4bd6-a061-99f087aebf7e",
   "scope": "openid"
}

Other timestamps/expirations are fine however (e.g., access token and KEYCLOAK_IDENTITY cookie in the same request showed OK).

I stumbled across this issue by recognizing a frequent "hard" refresh of my frontend client, since the regular refresh of the access token fails (due to the invalid refresh token, obviously). This led me to investigating said problem with the refesh token.

Noteworthy:

  • When logging out of the Keycloak session completely, the problem is gone on next login (exp timestamp with proper offset in the future)
  • We use an IdP during login (Azure AD)

Version

17.0.1

Expected behavior

Refresh token expiration to be positive and as configured, e.g.:
"refresh_expires_in": 1800

Actual behavior

Refresh token expiration is negative, e.g.:
"refresh_expires_in": -15933

How to Reproduce?

Token lifespan relevant realm config:

  "revokeRefreshToken": false,
  "refreshTokenMaxReuse": 0,
  "accessTokenLifespan": 300,
  "accessTokenLifespanForImplicitFlow": 900,
  "ssoSessionIdleTimeout": 43200,
  "ssoSessionMaxLifespan": 86400,
  "ssoSessionIdleTimeoutRememberMe": 0,
  "ssoSessionMaxLifespanRememberMe": 0,
  "offlineSessionIdleTimeout": 2592000,
  "offlineSessionMaxLifespanEnabled": false,
  "offlineSessionMaxLifespan": 5184000,
  "clientSessionIdleTimeout": 1800,
  "clientSessionMaxLifespan": 36000,
  "clientOfflineSessionIdleTimeout": 0,
  "clientOfflineSessionMaxLifespan": 0,
  "accessCodeLifespan": 60,
  "accessCodeLifespanUserAction": 300,
  "accessCodeLifespanLogin": 1800,

Realm client config:

    {
      "clientId": "my-client",
      "description": "",
      "rootUrl": "redacted",
      "adminUrl": "",
      "baseUrl": "/",
      "surrogateAuthRequired": false,
      "enabled": true,
      "alwaysDisplayInConsole": true,
      "clientAuthenticatorType": "client-secret",
      "redirectUris": redacted,
      "webOrigins": [
        "+"
      ],
      "notBefore": 0,
      "bearerOnly": false,
      "consentRequired": false,
      "standardFlowEnabled": true,
      "implicitFlowEnabled": false,
      "directAccessGrantsEnabled": false,
      "serviceAccountsEnabled": false,
      "publicClient": true,
      "frontchannelLogout": false,
      "protocol": "openid-connect",
      "attributes": {
        "saml.assertion.signature": "false",
        "saml.force.post.binding": "false",
        "saml.multivalued.roles": "false",
        "saml.encrypt": "false",
        "oauth2.device.authorization.grant.enabled": "false",
        "backchannel.logout.revoke.offline.tokens": "false",
        "saml.server.signature": "false",
        "saml.server.signature.keyinfo.ext": "false",
        "use.refresh.tokens": "true",
        "exclude.session.state.from.auth.response": "false",
        "oidc.ciba.grant.enabled": "false",
        "saml.artifact.binding": "false",
        "backchannel.logout.session.required": "true",
        "client_credentials.use_refresh_token": "false",
        "saml_force_name_id_format": "false",
        "saml.client.signature": "false",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "false",
        "display.on.consent.screen": "false",
        "saml.onetimeuse.condition": "false"
      },
      "fullScopeAllowed": false,
      "nodeReRegistrationTimeout": -1
    },

Client application:

  • Chrome on macOS

Anything else?

Interestingly, until now, I only happened to experience this problem with Chrome on macOS. No issue so far on Chrome on Windows.
On the macOS machine, however, it also does not occur consistently. We have multiple Keycloak instances (for different environments), with the exact same Keycloak deployed (17.0.1) and identical realm configurations. On some instances I face the problem, while others are fine. Also, the problem is not always present.

I somewhat feel like there's a correlation that this problem occurs when I continue using the affected web frontend after the macbook was on standby/hibernate for a couple of hours.

@alexwais alexwais added kind/bug Categorizes a PR related to a bug status/triage labels May 14, 2022
@alexwais alexwais changed the title Negative refresh token expiration timestamp Negative refresh token expiration May 14, 2022
@alexwais alexwais changed the title Negative refresh token expiration Negative refresh token expiration (exp timestamp in the past) May 14, 2022
@stianst stianst added the area/oidc Indicates an issue on OIDC area label May 18, 2022
@miglocatiq
Copy link

I am experiencing a similar problem. I get negative "refresh_expires_in" values when I set my Client_session_max lower than my SSO_Session_max. The numbers shown in the response seem to be the settings I use in de Client_Session_Max and the Client_Session_Idle, however my session is only being ended when the SSO_Session_Max time is reached. Between My Client_Session_Max expiring and my SSO_Session_Max still being valid I see the "refresh_expires_in" value going down into negative numbers.

valkum added a commit to valkum/keycloak that referenced this issue Jun 17, 2022
When the client session max lifetime is set shorter than the sso session
max lifetime, at the point where the client session gets terminated, the
refresh token endpoint returns 400. When the user then tries to login
again the SSO remembers that there is a session but the resulting
refresh token of the token request has a negative expire time.

Now the getRefreshExpiration method correctly uses the clientSession to
calculate the expire time for the refresh token.

Fixes keycloak#11990
@pehunka
Copy link

pehunka commented Jul 25, 2022

I'm getting negative expiration_in for following scenario.

I'm trying to get access token with refresh_token grant where refresh token is offline token (refresh token with scope=offline_access).

I thought that SSO Max should not impact offline session. I have review all expiration times and I'm not able to figure it out what is going on. I tried to set offline session max from unlimited to 120 days without success.

Ream timeouts:

"revokeRefreshToken": false,
  "refreshTokenMaxReuse": 0,
  "accessTokenLifespan": 180,
  "accessTokenLifespanForImplicitFlow": 300,
  "ssoSessionIdleTimeout": 18000,
  "ssoSessionMaxLifespan": 36000,
  "ssoSessionIdleTimeoutRememberMe": 0,
  "ssoSessionMaxLifespanRememberMe": 0,
  "offlineSessionIdleTimeout": 2592000,
  "offlineSessionMaxLifespanEnabled": true,
  "offlineSessionMaxLifespan": 10368000,
  "clientSessionIdleTimeout": 420,
  "clientSessionMaxLifespan": 900,
  "accessCodeLifespan": 60,
  "accessCodeLifespanUserAction": 300,
  "accessCodeLifespanLogin": 1800,
  "actionTokenGeneratedByAdminLifespan": 43200,
  "actionTokenGeneratedByUserLifespan": 300,

@krlm
Copy link

krlm commented Oct 25, 2022

I've encountered similar problem but with KEYCLOAK_IDENTITY cookies. Cookie with _LEGACY suffix looks OK, the other one has exp set to weak earlier than iat and point to 01:01:00. When such pair of cookies is sent then connection is closed.

curl: (56) OpenSSL SSL_read: Connection reset by peer, errno 104

Users started reporting such problem right after upgrade from v13.1 to 18.1

@rmartinc rmartinc added this to the 22.0.0 milestone Mar 7, 2023
rmartinc pushed a commit to rmartinc/keycloak that referenced this issue Mar 8, 2023
When the client session max lifetime is set shorter than the sso session
max lifetime, at the point where the client session gets terminated, the
refresh token endpoint returns 400. When the user then tries to login
again the SSO remembers that there is a session but the resulting
refresh token of the token request has a negative expire time.

Now the getRefreshExpiration method correctly uses the clientSession to
calculate the expire time for the refresh token.

Fixes keycloak#11990
rmartinc pushed a commit to rmartinc/keycloak that referenced this issue Mar 8, 2023
When the client session max lifetime is set shorter than the sso session
max lifetime, at the point where the client session gets terminated, the
refresh token endpoint returns 400. When the user then tries to login
again the SSO remembers that there is a session but the resulting
refresh token of the token request has a negative expire time.

Now the getRefreshExpiration method correctly uses the clientSession to
calculate the expire time for the refresh token.

Fixes keycloak#11990
rmartinc added a commit to rmartinc/keycloak that referenced this issue Mar 8, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue Mar 9, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue Mar 10, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue Mar 13, 2023
@Jojoooo1
Copy link

@pehunka we are having the exact same error, did you find any workaround ?

rmartinc pushed a commit to rmartinc/keycloak that referenced this issue May 24, 2023
When the client session max lifetime is set shorter than the sso session
max lifetime, at the point where the client session gets terminated, the
refresh token endpoint returns 400. When the user then tries to login
again the SSO remembers that there is a session but the resulting
refresh token of the token request has a negative expire time.

Now the getRefreshExpiration method correctly uses the clientSession to
calculate the expire time for the refresh token.

Fixes keycloak#11990
rmartinc added a commit to rmartinc/keycloak that referenced this issue May 24, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue May 27, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue May 27, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue May 29, 2023
rmartinc added a commit to rmartinc/keycloak that referenced this issue May 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/oidc Indicates an issue on OIDC area kind/bug Categorizes a PR related to a bug team/rh-iam
Projects
None yet
8 participants