content: package com.anita.multipleauthapi.security.oauth2;
  
  import jakarta.servlet.http.HttpServletRequest;
  import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
  import org.springframework.security.crypto.keygen.StringKeyGenerator;
  import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
  import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver;
  import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;
  import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
  import org.springframework.security.oauth2.core.endpoint.PkceParameterNames;
  
  import java.nio.charset.StandardCharsets;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Base64;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Objects;
  
  public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver {
  
      private final OAuth2AuthorizationRequestResolver defaultResolver;
      private final StringKeyGenerator secureKeyGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96);
  
      public CustomAuthorizationRequestResolver(ClientRegistrationRepository repo, String authorizationRequestBaseUri) {
          defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(repo, authorizationRequestBaseUri);
      }
  
      @Override
      public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
          OAuth2AuthorizationRequest req = defaultResolver.resolve(request);
          return customizeAuthorizationRequest(req);
      }
  
      @Override
      public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) {
          OAuth2AuthorizationRequest req = defaultResolver.resolve(request, clientRegistrationId);
          return customizeAuthorizationRequest(req);
      }
  
  
      private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest req) {
          if (Objects.isNull(req)) {
              return null;
          }
  
          Map<String, Object> attributes = new HashMap<>(req.getAttributes());
          Map<String, Object> additionalParameters = new HashMap<>(req.getAdditionalParameters());
          addPkceParameters(attributes, additionalParameters);
          return OAuth2AuthorizationRequest.from(req)
                  .attributes(attributes)
                  .additionalParameters(additionalParameters)
                  .build();
      }
  
      private void addPkceParameters(Map<String, Object> attributes, Map<String, Object> additionalParameters) {
          String codeVerifier = this.secureKeyGenerator.generateKey();
          attributes.put(PkceParameterNames.CODE_VERIFIER, codeVerifier);
          try {
              String codeChallenge = createHash(codeVerifier);
              additionalParameters.put(PkceParameterNames.CODE_CHALLENGE, codeChallenge);
              additionalParameters.put(PkceParameterNames.CODE_CHALLENGE_METHOD, "S256");
          } catch (NoSuchAlgorithmException e) {
              additionalParameters.put(PkceParameterNames.CODE_CHALLENGE, codeVerifier);
          }
      }
  
      private static String createHash(String value) throws NoSuchAlgorithmException {
          MessageDigest md = MessageDigest.getInstance("SHA-256");
          byte[] digest = md.digest(value.getBytes(StandardCharsets.US_ASCII));
          return Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
      }
  }
  