We should consider adding support for configuring OAuth2AuthorizationRequestResolver by publishing a bean. This would simplify this customization and allow for the following configuration:

@Bean
public OAuth2AuthorizationRequestResolver authorizationRequestResolver(
        ClientRegistrationRepository clientRegistrationRepository) {

    var authorizationRequestResolver =
        new DefaultOAuth2AuthorizationRequestResolver(
            clientRegistrationRepository,
            OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI);
    authorizationRequestResolver.setAuthorizationRequestCustomizer(
        OAuth2AuthorizationRequestCustomizers.withPkce());

    return authorizationRequestResolver;
}

The same would apply with the reactive stack and ServerOAuth2AuthorizationRequestResolver. See this comment for additional context. cc @randomstuff

Comment From: knoobie

@sjohnr Sorry for hijacking this issue.. because it's quite recent - I was thinking abour asking here before creating a new one because it is somehow related.

We are currently supporting multiple client registrations for our application and each client registration requires us to customize the Request with e.g. amr values. Because each client requires different amr values, we have some dirty hack in place because the customizer has no access to the currentClient it has to be build for.. With multiple Beans this issue might occur more frequently for people as well.

  private Consumer<Builder> authorizationRequestCustomizer() {
    return customizer -> {

      // We need something to distinguish between the registrations (which is not accessible from the builder without building the config
      var tempConfig = customizer.build();
      if (!tempConfig.getAttributes().containsKey(OAuth2ParameterNames.REGISTRATION_ID)) {
        return;
      }
      switch (tempConfig.getAttributes().get(OAuth2ParameterNames.REGISTRATION_ID).toString()) {
        case "a" -> {
          customizer.attributes(Map.of("amr", "a"));
        }
        case "b" -> {
          customizer.attributes(Map.of("amr", "b"));
        }
      }
    };
  }

Comment From: sjohnr

@knoobie you can also access the attributes via the builder method that takes a Consumer, like so:

private static Consumer<OAuth2AuthorizationRequest.Builder> authorizationRequestCustomizer() {
    return (builder) -> builder.attributes((attributes) -> {
        if (!attributes.containsKey(OAuth2ParameterNames.REGISTRATION_ID)) {
            return;
        }

        String registrationId = attributes.get(OAuth2ParameterNames.REGISTRATION_ID).toString();
        // ...
    });
}

Comment From: knoobie

Oh... Interesting idea! Thanks!