Confused about Offline Token behavior

Hello everyone,

I’d like to get some clarification about the behavior of Offline Tokens and how to properly deal with them as my experience doesn’t really seem to match what the documentation suggests.

Given: A Server that acts via the admin API and a Client that acts for itself.

  1. The Server creates an Offline Token using the “protocol/openid-connect/token” endpoint with grant_type “token-exchange”, requested_token_type “refresh_token” and having “offline_access” in its scope.
  2. As a result, two Sessions appear in the admin console: an OFFLINE and a REGULAR one. First confusion here: Why are two generated?
  3. The Server now provides the Client with the acquired token. The client uses this token to do its grant_type=“refresh_token” request, also setting the scope “offline_access”. The request is successful and an idToken given, no changes are visible in the admin console.
  4. The client can now log out using the provided endSessionEndpoint and giving the idToken as id_token_hint. Response 200, all OK. Again, no change visible in the admin console.
  5. If the server attempts a logout in the name of the client using the keycloak-admin-client UserResource.logout() method, the REGULAR session disappears. The OFFLINE session remains in the console, but is apparently invalidated with Keycloak 23 (but not in 21?) → The Client trying to do a refresh_token request afterwards fails with “stale token”
  6. If the server instead just removes all sessions, the admin console looks the same, but the offline token is still valid and the client can still do all requests.

Is everything as explained here expected behavior? What purpose does the REGULAR session have in this case? Shouldn’t it still be represented that a client is active in a session with the offline token or not? Are different requests needed to properly use offline tokens?

Any advice would be appreciated, thanks in advance.

You can also request an offline token from the begining using the scope parameter at the start of OAuth flow.

An offline token is a special type of refresh token that allows a client to refresh an access token even after the user has logged out. This can be useful for an application to perform time-consuming actions on behalf of a user (example performing sync and backup operations). This special refresh token remains valid for up to 60 days by default. So to manage its lifespan, Keycloak requires a dedicated session, and that’s why you have 2 different sessions : the first one will be used for the current session, and the second for the offline_access.

I’m not quite sure what you mean, but from a client perspective, he can still renew tokens even if the user has been logged out.

Again, I’m not quite sure what you mean, but the offline token is used in the refresh operation and not to access protected resources.

Hope that clarify things.

Thanks a lot for taking the time to clarify things!

That’s also what I got from the documentation → Is it a bug in Keycloak 23 then that using UserResource.logout() from the Keycloak admin api leads to “stale token” error responses when doing further refresh_token requests with the offline token? Or is my approach wrong here? I switched to specifically requesting all active sessions for the user and deleting them instead to get around this issue, but a logout still seems cleaner to me. Or does the behavior differ intentionally when an admin does the logout vs. the user itself? In my use-case, the Server (admin) has to do it for the client.

Aah I see, so if I just do this request to prepare a token that a Client (with no input capabilities to do its own flow) can request and use for offline work in the future, I can basically immediately end the session, is that correct?

This is just about the visualization of sessions in the admin console, maybe I’m misunderstanding the session representation then: My assumption is that when I do a refresh_token request and get an idToken and an access token, that this request also creates/refreshes an active session I can see in the admin console. However, if I deleted the REGULAR session of an Offline Token so that only OFFLINE remains, nothing visibly changes in the admin console. My expectation was that I can somehow see that a user requested an Access Token and is currently active in that session, and that it looks different after a logout. So I’m just asking about the capability to monitor in the admin console here whether or not an OfflineToken is currently actively used, i.e. someone is working with an AccessToken based on it. Is that a bit clearer?
Essentially, I thought that if I only see a OFFLINE session in the console and then use the OfflineToken in a refresh_token request, that the console now also shows a REGULAR session again until the user logs out or something along those lines. But nothing changes.

I hope I made myself a bit clearer, I appreciate your time.

Yes that’s correct.

If you are looking for a way to revoke an offline session, you can check this discussion