Describe the bug It is possible to use "urn:ietf:params:oauth:grant-type:jwt-bearer" as a valid authorization-grant-type. However, Spring-Security does nothing if the grant_type uses the "short" notation : "jwt-bearer". In fact, the filter will just return an empty Mono in this situation)

The authentication POST call is then forged using the authorization-grant-type value as the "grant_type" field value. Some identity providers expect to see the exact string "jwt-bearer", which is problematic because there's no way to configure spring-security oauth client as such.

To Reproduce

Set a spring-security oauth-client project using those application.yml configurations. You'll see that nothing happens, regarding the authentication tokens fetch operations, even if we apply .oauth2Client() in a SecurityWebFilterChain bean.

Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application .class, args);
    }
}

application.yml

security:
    oauth2:
      client:
        registration:
          <provider>:
            client-authentication-method : client_secret_post
            authorization-grant-type: jwt-bearer
            client-id: <client id>
            client-secret: <client secret>

Configuration Beans

@Configuration
@EnableWebFluxSecurity
public class OAuth2ClientSecurityConfiguration {

    @Bean
    public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
            ReactiveClientRegistrationRepository clientRegistrationRepository,
            ServerOAuth2AuthorizedClientRepository authorizedClientService) {

        var jwtBearerAuthorizedClientProvider  =
               new JwtBearerReactiveOAuth2AuthorizedClientProvider();

        ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
                ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
                        .provider(jwtBearerAuthorizedClientProvider)
                        .build();

        var authorizedClientManager =
                new DefaultReactiveOAuth2AuthorizedClientManager(
                        clientRegistrationRepository, authorizedClientService);
        authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

        return authorizedClientManager;
    }

    @Bean
    public SecurityWebFilterChain configure(ServerHttpSecurity http) {
        return http
                .oauth2Client()
                .and()
                .build();
    }

    @Bean
    public WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        oauth.setDefaultClientRegistrationId(<provider>);

        return WebClient.builder()
                .filter(oauth)
                .build();

    }
}

Expected behavior The jwt-bearer flow should be enabled when using the authorization-grant-type "jwt-bearer", exactly how it actually does when we use "urn:ietf:params:oauth:grant-type:jwt-bearer"

Comment From: alexis-valois

It appears to be caused by that line, in JwtBearerReactiveOAuth2AuthorizedClientProvider.java : https://github.com/spring-projects/spring-security/blob/1631cac1506d7fdda1f3864357075af4965a78cd/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/JwtBearerReactiveOAuth2AuthorizedClientProvider.java#L71

AuthorizationGrantType.JWT_BEARER is a hardcoded value that evaluates to "urn:ietf:params:oauth:grant-type:jwt-bearer"

How about we just add another enty in AuthorizationGrantType, let's say

public static final AuthorizationGrantType JWT_BEARER_COMMON_NAME = new AuthorizationGrantType(
            "jwt-bearer");

and just add a OR in the previous condition ?

I would gladly submit a pull request for it :)

Comment From: jgrandja

Closing as per comment