title: Spring OAuth2 Security - Client Credentials - Custom AuthenticationProvider
body: <p>I am writing an authentication service in our service architecture that will basically be an implementation of Spring OAuth2 Authorization Server.  From this I will need to authenticate provided credentials against many different sources to support a legacy environment.</p>
  
  <p>I am primarily concentrated on using the client credentials flow where users (other services) will use their own credentials to obtain a token and, for the time being, will not require OAuth2's authorize or refresh.</p>
  
  <p>I have successfully been able to spin up a Spring Boot application that is protected with Spring Security (<code>@EnableWebSecurity</code>).  I have also successfully set up the Authorization Server (<code>@EnableAuthorizationServer</code>) which provides the necessary endpoints (<code>/oauth/token</code>) to provide a token.  I have been able to configure the Authorization Server with in memory and custom ClientDetailsService to successfully get a token.  This is all just to demonstrate to myself that I can get something working.</p>
  
  <p>My problem is that I need to authenticate the credentials against a custom source.  I do not have direct access to the passwords and certainly do not know how they are encoded.</p>
  
  <p>After digging through the Spring code, I could see that through the <code>DaoAuthenticationProvider</code>, it accomplishes authentication by calling <code>PasswordEncoder.matches()</code>.  Unfortunately, I do not get a password from the <code>ClientDetailsService</code>, nor do I know how the password is encoded if I did, so a custom <code>PasswordEncoder</code> does not do me much good (also I would need match in multiple ways with only one <code>PasswordEncoder</code>).  So, I'm left with defining my own <code>AuthenticationProvider</code> (or <code>AuthenticationManager</code>).</p>
  
  <p>I was able to implement my own <code>AuthenticationProvider</code> and provide that to the Spring Security configuration.  This worked perfectly and I was able to defer the authentication to my own provider which can do whatever I see fit (such as delegating to another service to authenticate), but this only worked for the non-OAuth2 endpoints.</p>
  
  <p>Now this is where everything starts to fall apart.  For whatever reason, I cannot get the <code>/oauth/token</code> endpoint to use the defined <code>AuthenticationManager</code> or <code>AuthenticationProvider</code>s that I supply.  It always defaults to an <code>AuthenticationManger</code> with <code>AnonymousAuthenticationProvider</code> and <code>DaoAuthenticationProvider</code>.</p>
  
  <p><strong>WebSecurity</strong></p>
  
  <p>Not much interesting here.  I'm exposing the authentication manager globally in an attempt to register it in the OAuth2 configuration. I've left in some commented code to show some other things I've tried, but they all pretty much accomplish the same thing: it works with everything but the OAuth2 endpoints.</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  
      @Autowired
      public AuthenticationProvider customAuthenticationProvider;
  
      @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
      @Override
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
  //      return new ProviderManager(Arrays.asList(customAuthenticationProvider));
      }
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
              .authorizeRequests()
              .anyRequest()
              .authenticated()
          .and()
              .httpBasic();
      }
  
      @Override
      public void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth
                  .authenticationProvider(customAuthenticationProvider);
      }
  
  //   @Autowired
  //   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  //       auth.authenticationProvider(customAuthenticationProvider);
  //   }
  }
  </code></pre>
  
  <p><strong>AuthServer</strong></p>
  
  <p>I've stripped this down to what I believe should be the correct configuration.  I've purposefully left out <code>ClientDetailsService</code> as it's part of the provider configuration and it is working properly.  I'm ignoring the <code>TokenStore</code> and using the defaults until I can get authentication out of the way.  Again, the <code>authenticationManager</code> here should be the global one exposed from WebSecurity.  I've also tried creating a new <code>ProviderManager</code> in the endpoints configurer, but that also did not work for me.</p>
  
  <pre><code>@Configuration
  @EnableAuthorizationServer
  public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
  
      @Autowired
      private AuthenticationManager authenticationManager;
  
      @Override
      public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {        
          oauthServer
              .tokenKeyAccess("permitAll()")
              .checkTokenAccess("permitAll()")
          ;
      }
  
      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
          endpoints.authenticationManager(authenticationManager);
      }
  }
  </code></pre>
  
  <p>I've also tried extending <code>AuthorizationServerSecurityConfiguration</code> without success:</p>
  
  <pre><code>@Configuration
  @EnableAuthorizationServer
  public class AuthServerConfig2 extends AuthorizationServerSecurityConfiguration {
  
      @Autowired
      public AuthenticationProvider customAuthenticationProvider;
  
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.authenticationProvider(customAuthenticationProvider);
      }
  }
  </code></pre>
  
  <p>I would expect my custom <code>AuthenticationProvider</code> would show in the list, but it will not with everything I've tried.</p>
  
  <p>This may be intentional, but if that is the case, what is the correct way to go about providing custom authentication schemes?</p>
  
  <p>I would really like to avoid it, but am I truly required to implement a custom filter and bypass all of the nice things Spring provides?  If yes, how would I go about doing that?</p>