title: Spring Security Authentication Server with multiple authentication providers for client_credentials
body: <p>I am trying to setup an authentication server using Spring Security authentication and need to have multiple authentication providers for client_credentials.</p>
  
  <p>I have done quite a bit of searching and have yet to find how to configure spring security to add my custom authentication provider to the client credentials authentication provider list.  Every approach I found results in the same 2 providers for the client credentials authentication.  The anonymous and the dao authentication providers.</p>
  
  <p>I would appreciate any help in figuring out how to configure the the spring security authentication server for multiple client credential authentication providers.</p>
  
  <p>AuthorizationServerConfig</p>
  
  <pre><code>@Configuration
  @EnableAuthorizationServer
  public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter 
  {
      @Autowired
      @Qualifier("authenticationManagerBean")
      private AuthenticationManager authenticationManager;
  
      @Override
      public void configure(final AuthorizationServerSecurityConfigurer security) throws Exception {
          security.tokenKeyAccess("permitAll()")
              .checkTokenAccess("isAuthenticated()")
              .passwordEncoder(passwordEncoder())
              .allowFormAuthenticationForClients();
      }
  
      @Override
      public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
          clients.inMemory()
  
              .withClient("sampleClientId").authorizedGrantTypes("implicit")
              .scopes("read", "write", "foo", "bar")
              .autoApprove(false)
              .accessTokenValiditySeconds(3600)
              .redirectUris("http://localhost:8083/")
  
              .and()
  
              .withClient("fooClientIdPassword")
              .secret(passwordEncoder().encode("secret"))
              .authorizedGrantTypes("password", "authorization_code", "refresh_token")
              .scopes("foo", "read", "write")
              .accessTokenValiditySeconds(3600)       // 1 hour
              .refreshTokenValiditySeconds(2592000)   // 30 days
              .redirectUris("xxx")
  
              .and()
  
              .withClient("barClientIdPassword")
              .secret(passwordEncoder().encode("secret"))
              .authorizedGrantTypes("client_credentials", "refresh_token")
              .scopes("bar", "read", "write")
              .resourceIds("kip-apis")
              .accessTokenValiditySeconds(3600)       // 1 hour
              .refreshTokenValiditySeconds(2592000)   // 30 days
  
              .and()
  
              .withClient("testImplicitClientId")
              .autoApprove(true)
              .authorizedGrantTypes("implicit")
              .scopes("read", "write", "foo", "bar")
              .redirectUris("xxx");
      }
  
      @Override
      public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
          final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
          tokenEnhancerChain
              .setTokenEnhancers(Arrays.asList(tokenEnhancer(), accessTokenConverter()));
  
          endpoints.authenticationManager(authenticationManager)
              .tokenServices(tokenServices())
              .tokenStore(tokenStore())
              .tokenEnhancer(tokenEnhancerChain);
      }
  
      @Bean
      public TokenStore tokenStore() {
          return new JwtTokenStore(accessTokenConverter());
      }
  
      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
           JwtAccessTokenConverter converter = new JwtAccessTokenConverter();        
          converter.setSigningKey("123");                
          return converter;
      }
  
      @Bean
      public TokenEnhancer tokenEnhancer() {
          return new CustomTokenEnhancer();
      }
  
      @Bean
      @Primary
      public DefaultTokenServices tokenServices() {
          final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
          defaultTokenServices.setTokenStore(tokenStore());
          defaultTokenServices.setSupportRefreshToken(true);
          defaultTokenServices.setTokenEnhancer(accessTokenConverter());
          return defaultTokenServices;
     }
  
     @Bean
     public BCryptPasswordEncoder passwordEncoder() {
         return new BCryptPasswordEncoder();
     }
  }
  </code></pre>
  
  <p>WebSecurityConfig:</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity( debug = true )  // turn off the default configuration 
  public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
      @Autowired
      private BCryptPasswordEncoder passwordEncoder;
  
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http
              .formLogin().disable() // disable form authentication
              .anonymous().disable() // disable anonymous user
              .authorizeRequests().anyRequest().denyAll(); // denying all access
      }
  
      @Autowired
      public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
          auth.inMemoryAuthentication()
            .withUser("john").password(passwordEncoder.encode("123")).roles("USER").and()
            .withUser("tom").password(passwordEncoder.encode("111")).roles("ADMIN").and()
            .withUser("user1").password(passwordEncoder.encode("pass")).roles("USER").and()
            .withUser("admin").password(passwordEncoder.encode("nimda")).roles("ADMIN");
      }
  
      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
      }    
  }
  </code></pre>
  
  <p>I have tried a few options for trying to add an additional authentication provider for the client credentials grant.  Such as in the WebSecurityConfig ...</p>
  
  <pre><code>@Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception 
  {
      auth.authenticationProvider(customDaoAuthenticationProvider);
  }
  </code></pre>
  
  <p>It didn't work and when stepping through the authentication for client_credentials I didn't see the custom one added to the provider list, just the anonymous and dao authentication providers.</p>