content: package org.example.authserver;
  
  import lombok.extern.slf4j.Slf4j;
  import org.springframework.security.authentication.AuthenticationProvider;
  import org.springframework.security.core.Authentication;
  import org.springframework.security.core.AuthenticationException;
  import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
  import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
  import org.springframework.security.oauth2.core.OAuth2Error;
  import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
  import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
  import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
  import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken;
  import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
  import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
  import org.springframework.util.Assert;
  
  @Slf4j
  public final class PublicClientRefreshTokenAuthenticationProvider implements AuthenticationProvider {
  
      private static final String ERROR_URI = "https://datatracker.ietf.org/doc/html/rfc6749#section-3.2.1";
  
      private final RegisteredClientRepository registeredClientRepository;
  
      public PublicClientRefreshTokenAuthenticationProvider(RegisteredClientRepository registeredClientRepository, OAuth2AuthorizationService authorizationService) {
          Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
          Assert.notNull(authorizationService, "authorizationService cannot be null");
          this.registeredClientRepository = registeredClientRepository;
      }
  
      @Override
      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
          // implementation is taken from PublicClientAuthenticationProvider
          // ---> removed the PKCE requirement
  
          OAuth2ClientAuthenticationToken clientAuthentication = (OAuth2ClientAuthenticationToken) authentication;
  
          if (!ClientAuthenticationMethod.NONE.equals(clientAuthentication.getClientAuthenticationMethod())) {
              return null;
          }
  
          String clientId = clientAuthentication.getPrincipal().toString();
          RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
          if (registeredClient == null) {
              throwInvalidClient(OAuth2ParameterNames.CLIENT_ID);
          }
  
          log.trace("Retrieved registered client");
  
          if (!registeredClient.getClientAuthenticationMethods().contains(clientAuthentication.getClientAuthenticationMethod())) {
              throwInvalidClient("authentication_method");
          }
  
          log.trace("Validated client authentication parameters");
  
          log.trace("Authenticated public client");
  
          return new OAuth2ClientAuthenticationToken(registeredClient, clientAuthentication.getClientAuthenticationMethod(), null);
      }
  
      @Override
      public boolean supports(Class<?> authentication) {
          return OAuth2ClientAuthenticationToken.class.isAssignableFrom(authentication);
      }
  
      private static void throwInvalidClient(String parameterName) {
          OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_CLIENT, "Client authentication failed: " + parameterName, ERROR_URI);
          throw new OAuth2AuthenticationException(error);
      }
  }