Description
Describe the bug
Apparently, neither the ID token nor the userinfo
are updated during the refresh token flow in Spring clients with oauth2Login
. This has at least two consequences:
- the principal (
OidcUser
orOAuth2User
) might contain outdated data - in case of an RP-Initiated Logout, the
OidcClientInitiated(Server)LogoutSuccessHandler
might build a redirection URI to the authorization serverend_session_endpoint
with an expired or outdated ID token, in which case the second part of the logout fails and the user session on the OpenID Provider might not be ended.
Additional context about ID tokens
ID tokens are JWTs and, as with all JWTs, they expire.
During RP-Initiated Logout, OpenID Providers SHOULD (not MUST) accept ID tokens even when the exp time has passed. This means that some OPs might not accept expired tokens and that clients would better do their best to send valid tokens.
Also, aside from expiration considerations, most OPs refreshing ID tokens accept only the last token they issued for a client. So when a new ID token is returned as part of a refresh token flow, the client should use this last issued ID token to build the RP-Initiated Logout location URI.
Last, I know no constraint in the specs about the different tokens relative lifespans. As a consequence, it seems possible that an ID token expires before the access one. And as far as I understood the source, the RefreshToken(Reactive)OAuth2AuthorizedClientProvider
refreshes tokens only if the access token expired which leaves room for expired ID token in the security context.
To Reproduce
Using an authorization server refreshing ID token as part of the refresh token flow (Keyckloak is one, and, according to the Stackoverflow question linked below, Spring Authorization Server seems to be another):
- login to an
oauth2Client
configured withoauth2Login
and RP-Initated Logout - wait until the access token is expired
- have refresh token flow executed. Using the
(Reactive)OAuth2AuthorizedClientManager
to retrieve the access token - like Spring Cloud GatewayTokenRelay=
filter does - is enough. - initiate RP-Initiated Logout (send a
POST
request to the/logout
endpoint)
Expected behavior
- tokens should be refreshed if either the access or the ID token has expired (or will before the
clockSkew
) - if the security context contains an ID token (the principal is an
OidcUser
) and if the refresh token response contains an ID token, then the ID token in the security context should be updated - redirection to the authorization server
end_session_endpoint
should be built with the last issued ID token
The OidcClientInitiated(Server)LogoutSuccessHandler
currently uses the (Reactive)ClientRegistrationRepository
which doesn't trigger the refresh token flow in case of expired tokens. Shouldn't it use the (Reactive)OAuth2AuthorizedClientManager
instead?
Some StackOverflow questions related to this issue:
- https://stackoverflow.com/questions/78901208/spring-authorization-server-refreshes-the-client-tokenoidc-id-token-when-the-a
- https://stackoverflow.com/questions/78685992/issue-in-spring-authorization-server-and-spring-cloud-gateway-refresh-token-flow
- https://stackoverflow.com/questions/77175866/spring-authorization-server-oidc-logout-not-working-after-refreshing-token-in-sp
- https://stackoverflow.com/questions/77665448/oidc-rp-initiated-logout-doesnt-work-once-the-first-access-token-got-refreshed
Metadata
Metadata
Assignees
Labels
Type
Projects
Status