This comment put me on track of something interesting.
I have Keycloak 21.0.2 / next-auth 4.22.1 with a next 13.1.6 app
When I in Client settings (overriding Realm settings) set
- Accesstoken lifespan to 1 minute
- Client Session Idle to 2 minutes
- Client session Max to 3 minutes (overriding Realm: SSO Session Max=10 hours)
After a minute and some seconds I navigate around, and a new access token is issued (refresh token exchange). The page starts LOOPING with { error: ‘invalid_grant’, error_description: ‘Token is not active’ } in the terminal as response to the token exchange.
Interestingly, the refresh token here is shorter lived than the access token:
expires_in: 60,
refresh_expires_in: 46, // NOTE refresh_token is shorter lived.
HOWEVER, when I set Realm to SSO Session Max = 3 minutes and override:
- Accesstoken lifespan to 1 minute
- Client Session Idle to 2 minutes
then the refreshtoken is [correctly, I think] set to the access token expiry after a couple refreshes, and the page does NOT loop. It navigates to the SSO signon page (Keycloak page).
expires_in: 33,
refresh_expires_in: 33,
In summary, If I override SSO Session Max with Client Session Max of 3 minutes, after the Session maxes out after 3 minutes I get
- refresh token exchange fails with { error: ‘invalid_grant’, error_description: ‘Token is not active’ } which is expected, but then
- signIn() seemingly tries to do a token exchange with the old refreshtoken, because I see that error, and never get to the SSO page
- even if I signOut(); and then signIn(), it STILL tries to do token exchange → eternal loop and never see the SSO page.
If I don’t override SSO Session Max, it behaves as expected.
(I would expect the two situations above to produce the same result, since SSO Session Max = 3 minutes or Client Session Max = 3 minutes should effectively be the same setting).
Will keep digging 
After quite some testing I filed Client Session Max isn't an exact override for SSO Session Max · Issue #21038 · keycloak/keycloak · GitHub on this; I think it must be a bug.