spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

AuthenticationPrincipalArgumentResolver has an outdated Authentication when OIDC ID Token is updated after refresh token

Open mpalourdio opened this issue 1 month ago • 4 comments

Hi,

In a plain oauth2Login() application (keycloak as IDP for example), after https://github.com/spring-projects/spring-security/pull/16589 has been implemented, consider the following example :

 @PostMapping("/fast")
    public Map<String, Object> getOidcUserPrincipal @AuthenticationPrincipal OidcUser principal1) {
        var principal2 = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        return principal1.getClaims();
    }

Once the OidcUserRefreshedEventListener#onApplicationEventhas been triggered, it's already too late for the AuthenticationPrincipalArgumentResolverto get the updated value, as it's not aware of the OidcUserRefreshedEvent.

So in the example above, with a very short Access Token Lifespan (let's say 2 minutes), principal1 might get the "before" refresh ID Token, whereas principal2 has the up-to-date value.

Shoot the endpoint before the refresh happens, values are in sync, wait a little, they are out-of-sync and so on.

Hope this is clear.

Thanks

mpalourdio avatar Nov 14 '25 21:11 mpalourdio

@mpalourdio Sorry but I don't fully understand the issue you are having.

Can you please put together a minimal sample or test that reproduces the issue and then I can look into it further.

jgrandja avatar Dec 02 '25 20:12 jgrandja

Yup, not very clear, I admit.

AuthenticationPrincipalArgumentResolver is the "helper" that let us inject @AuthenticationPrincipal OidcUser xxxx as argument of a method in a controller (or whatever @Bean) like in my example.

The problem is: If a user tries to access the endpoint in which we inject @AuthenticationPrincipal OidcUser xxxx, and the OidcUserRefreshedEventListener must be triggered because of the IDP token refresh policy (one or 2 minutes lifespan), the OidcUser xxxxxx that is resolved as the method argument by AuthenticationPrincipalArgumentResolver, ie. @AuthenticationPrincipal OidcUser xxxx, will be resolved before OidcUserRefreshedEventListener#onApplicationEvent happens.

The consequence is that @AuthenticationPrincipal OidcUser xxxxx is outdated once we enter the method, because the listeners have been triggered after AuthenticationPrincipalArgumentResolver resolves @AuthenticationPrincipal OidcUser xxxx`

Why ? I suppose that before triggering all the OIDC refresh workflow, @AuthenticationPrincipal OidcUser xxxx is resolved very soon in order to be injected as method parameter.

Hope this is clearer.

mpalourdio avatar Dec 02 '25 20:12 mpalourdio

@mpalourdio I now understand the issue but it's still not clear how your specific flow is working. This is why I asked in the previous comment:

Can you please put together a minimal sample or test that reproduces the issue and then I can look into it further.

If this is indeed a bug, then a test would need to be provided regardless as part of the fix. I'll wait on the sample or test and will then look into this further.

Just to clarify:

and the OidcUserRefreshedEventListener must be triggered because of the IDP token refresh policy

OidcUserRefreshedEventListener is ONLY triggered when a refresh_token grant flow is performed by the client. The refresh_token grant flow is triggered via RefreshTokenOAuth2AuthorizedClientProvider through an OAuth2AuthorizedClientManager.

jgrandja avatar Dec 03 '25 15:12 jgrandja

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-projects-issues avatar Dec 10 '25 15:12 spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

spring-projects-issues avatar Dec 17 '25 15:12 spring-projects-issues