spring-projects / spring-projects/spring-security
Provide API to enable OAuth2AuthorizationCodeGrantFilter to resolve the Authentication given the OAuth2AuthorizationCodeAuthenticationToken
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Please provide an API to enable OAuth2AuthorizationCodeGrantFilter to resolve the Authentication, given the OAuth2AuthorizationCodeAuthenticationToken. If present, this would be used to obtain the Authentication used to:
- construct the
OAuth2AuthorizedClient; and - save it via
OAuth2AuthorizedClientRepository
E.g.,
public void setAuthenticationResolver(Function<OAuth2AuthorizationCodeAuthenticationToken, Authentication> resolver) {
this.authenticationResolver = resolver;
}
This would be used in processAuthorizationResponse(...) as follows:
Authentication currentAuthentication;
if (authenticationResolver != null) {
currentAuthentication = authenticationResolver .apply(authenticationResult);
else {
// support the existing behaviour
currentAuthentication = this.securityContextHolderStrategy.getContext().getAuthentication();
}
String principalName = (currentAuthentication != null) ? currentAuthentication.getName() : "anonymousUser";
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
authenticationResult.getClientRegistration(), principalName, authenticationResult.getAccessToken(),
authenticationResult.getRefreshToken());
this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, currentAuthentication, request,
response);
Current Behavior
The current behaviour uses the securityContextHolderStrategy to resolve the authentication.
Context
This is related to https://stackoverflow.com/questions/75254595
I use JavaMail to send email via SMTP and monitor replies via IMAP for multiple accounts. This uses username and password authentication. I now need to add support for OAuth2, using the code grant flow.
I want to associate the email address of the user who granted access to their mailbox with the corresponding OAuth2AuthorizedClient, in order to get the appropriate access token when connecting to a mailbox.
The current behaviour of OAuth2AuthorizationCodeGrantFilter is insufficient, as it uses the securityContextHolderStrategy to determine the Authentication. In my case, this is the user logged into the webapp, whereas I want it to be the email address of the resource owner.
To work around this, I've duplicated OAuth2AuthorizationCodeGrantFilter and added:
private Authentication getAuthentication(OAuth2AuthorizationCodeAuthenticationToken authenticationResult) {
ClientRegistration clientRegistration = authenticationResult.getClientRegistration();
JwtDecoder decoder = tokenDecoderFactory.createDecoder(clientRegistration);
String idToken = (String) authenticationResult.getAdditionalParameters().get(OidcParameterNames.ID_TOKEN);
if (StringUtils.isEmpty(idToken)) {
OAuth2Error error = new OAuth2Error(
"invalid_id_token", "Missing (required) ID Token in Token Response for Client Registration: "
+ clientRegistration.getRegistrationId(), null);
throw new OAuth2AuthenticationException(error, error.toString());
}
Jwt jwt = decoder.decode(idToken);
String email = jwt.getClaimAsString("email");
if (StringUtils.isEmpty(email)) {
OAuth2Error error = new OAuth2Error(
"invalid_id_token", "Missing email in Token Response for Client Registration: "
+ clientRegistration.getRegistrationId(), null);
throw new OAuth2AuthenticationException(error, error.toString());
}
return new PreAuthenticatedAuthenticationToken(email, null, Collections.emptyList());
}
This is invoked within processAuthorizationResponse(...) follows:
Authentication authentication = getAuthentication(authenticationResult);
String principalName = authentication.getName();
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
authenticationResult.getClientRegistration(), principalName, authenticationResult.getAccessToken(),
authenticationResult.getRefreshToken());
this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, authentication, request, response);
To override the default code grant filter, I've added:
<security:custom-filter before="OAUTH2_AUTHORIZATION_CODE_GRANT_FILTER"
ref="myOauth2AuthorizationCodeGrantFilter"/>
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at OAuth2AuthorizationCodeGrantFilter.processAuthorizationResponse(...) and trace how securityContextHolderStrategy currently supplies Authentication, then inspect the OAuth2AuthorizedClient construction and repository save call. Done means the requested resolver API supports the resource-owner principal while preserving the existing fallback behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- authentication, backend, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100