Expected Behavior

Our current OAuth2 provider returns a custom claim for the roles, which I would like to convert.

Currently I cannot override the method here https://github.com/spring-projects/spring-security/blob/main/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java#L212 because the convert method is private.

Could this method be made protected or public or offer other alternatives to convert custom claims?

Current Behavior

Everything is private for the NimbusOpaqueTokenIntrospector so i have no chance to convert custom claims.

Context

Example what I we currently need to convert roles

   private Collection<GrantedAuthority> getAuthorities( final TokenIntrospectionSuccessResponse response, final Map<String, Object> claims ) {
      final Collection<GrantedAuthority> authorities = new ArrayList<>();
      if ( response.getScope() != null ) {
         final List<String> scopes = Collections.unmodifiableList( response.getScope().toStringList() );
         claims.put( SCOPE, scopes );

         for ( final String scope : scopes ) {
            authorities.add( new SimpleGrantedAuthority( authorityPrefix + scope ) );
         }
      }

      final List<String> roles = response.getStringListParameter( roleClaim );
      if ( !CollectionUtils.isEmpty( roles ) ) {
         claims.put( roleClaim, roles );
         roles.forEach( role -> authorities.add( new SimpleGrantedAuthority( rolePrefix + role ) ) );
      }
      return authorities;
   }

Comment From: jzheaux

Hi, @MelleD, thanks for the suggestion. As a side note, unless you need something Nimbus-specific, I'd recommend using SpringOpaqueTokenIntrospector.

And, in light of that, yes, I think it is reasonable to add a setter like this one to SpringOpaqueTokenIntrospector:

public void setAuthenticationConverter(Converter<OAuth2TokenIntrospectionClaimAccessor, OAuth2AuthenticatedPrincipal> converter)

SpringOpaqueTokenIntrospector would convert the claim set and then call this converter.

Then, your configuration would look something like:

@Bean 
OpaqueTokenIntrospector opaqueTokenIntrospector() {
    SpringOpaqueTokenIntrospector introspector = new SpringOpaqueTokenIntrospector();
    introspector.setAuthenticationConverter((accessor) -> {
        List<String> scopes = accessor.getScopes();
        // ... convert into authorities as needed
        return new OAuth2IntrospectionAuthenticatedPrincipal(accessor.getClaims(), authorities);
    });
    return introspector;
}

In this way, if folks need to do any further customization on the principal, they can do that as well in the same converter.

Are you able to provide a PR that makes these changes?

Comment From: MelleD

@jzheaux thanks for the quick reply. Let me double check the code. I was not aware of the SpringOpaqueTokenIntrospector. I'll check whether we need more customization.

Is there also the possibility of simply setting the converter as a bean without creating the SpringOpaqueTokenIntrospector?

Comment From: jzheaux

Perhaps in time, @MelleD. I prefer to move a bit slowly on that front given that publishing the OpaqueTokenIntrospector is already simple. Generally speaking, Spring Security picks up beans that are either cross-cutting in nature (like SecurityContextHolderStrategy) or map to a specific HttpSecurity DSL method (like OpaqueTokenIntrospector/.introspector()).

Comment From: MelleD

@ahmd-nabil thanks :).