Describe the bug We use AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager to manage oauth tokens sent to external service. Call flow is: * mobile aplication calls our service with application token (grant_type=client_credentials) * then our service calls external service using different application token (with different scopes, but also with grant_type=client_credentials)
When spring-security obtains the second token, we get following assertion in InMemoryReactiveOAuth2AuthorizedClientService:
Assert.hasText(principalName, "principalName cannot be empty");
Callstack is:
hasText:284, Assert (org.springframework.util)
loadAuthorizedClient:57, InMemoryReactiveOAuth2AuthorizedClientService (org.springframework.security.oauth2.client)
lambda$null$4:117, AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager (org.springframework.security.oauth2.client)
apply:-1, 600571723 (org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager$$Lambda$1321)
Our principal has type JwtAuthenticationToken with name = null. Name is null because jwt token has no subject (no claim "sub").
Example of our token:
{
"exp": 1587037291,
"user_name": "55381106",
"jti": "dea45b7b-5569-4db7-94b3-e2e78aaf4fc1",
"client_id": "android.1e9",
"scope": [
"openid",
"access_token_login"
]
}
In previous versions of spring we used ClientCredentialsAccessTokenProvider and above scenario worked without any problem.
Now we use spring-security-oauth2-client 5.3.1.RELEASE
Expected behavior AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager is able to get new access token even if input token has no subject.
Comment From: jgrandja
@zxspeccy This is expected behaviour -> "principalName cannot be empty".
The OAuth2AuthorizedClient requires the principalName since an access token is always associated with a principal. The ReactiveOAuth2AuthorizedClientService validates the principalName and is expected to fail if the principalName is not available.
The reason principalName is not available is because JwtAuthenticationToken.getName() will default to the sub claim, which is not available in the claims set of the Jwt, as per your token example above. What you need to do is specify that the user_name claim be used as the principalName.
Take a look at this sample that shows you how to configure the JwtDecoder to default to the user_name for JwtAuthenticationToken.getName().
I'm going to close this as answered but we can re-open if you are still having issues.
Comment From: zxspeccy
I applied claim converter and it works. Thank you for hint!