title: Single Sign On with Spring Security OAuth2 and JWT
body: <p>I am trying to implement Single Sign On with Spring Security OAuth2 and JWT.
  I use two separate applications:</p>
  
  <p>An Authorization Server – which is the central authentication mechanism</p>
  
  <p>Client Application: the applications using SSO</p>
  
  <p>When a user tries to access a secured page in the client app, they’ll be redirected to authenticate first, via the Authentication Server.</p>
  
  <p>And I am using the Authorization Code grant type out of OAuth2 to drive the delegation of authentication. </p>
  
  <p><strong>Authorization server:</strong></p>
  
  <pre><code>@Configuration
  @EnableAuthorizationServer
  public class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
  
    public static final Logger LOGGER = LoggerFactory.getLogger(AuthorizationServerConfigurerAdapter.class);
  
  
    @Autowired
    private AuthenticationManager authenticationManager;
  
  
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }
  
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("abcd");
        return converter;
    }
  
    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setTokenEnhancer(accessTokenConverter());
        return defaultTokenServices;
    }
  
    @Override
    public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
      clientDetailsServiceConfigurer
      .inMemory()
          .withClient("webapp")
          .secret("Pass")
          .authorizedGrantTypes("implicit", "refresh_token", "password", "authorization_code")
          .scopes("user_info")
          .autoApprove(true);
    }
  
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {    
      oauthServer.tokenKeyAccess("permitAll()")
      .checkTokenAccess("isAuthenticated()");
    }
  
  
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager);
    }
  
  }
  </code></pre>
  
  <p><em>Security Configuration on Authorization Server</em></p>
  
  <pre><code>@Configuration
  public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter  {
  
    @Value("${ldap.url}")
    private String ldapUrl;
  
    @Value("${ldap.userDnPatterns}")
    private String ldapUserDnPatterns;
  
    @Autowired
    private PersonService personService;
  
    @Autowired
    private RoleService roleService;
  
    @Override
    protected void configure(HttpSecurity http) throws Exception { // @formatter:off
        http.requestMatchers()
            .antMatchers("/login", "/oauth/authorize")
            .and()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .permitAll();
    } // @formatter:on
  
  
    @Bean(name = "authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
      return super.authenticationManagerBean();
    }
  
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth
       .authenticationProvider(this.ldapAndDatabaseAuthenticationProvider());
    }
  
    @Bean(name="ldapAuthenticationProvider")
    public AuthenticationProvider ldapAndDatabaseAuthenticationProvider(){
      LdapUserDetailsMapper userDetailsMapper = new LdapUserDetailsMapper();
      userDetailsMapper.setRoleAttributes(new String[]{"groupMembership"});
  
      LdapAndDatabaseAuthenticationProvider provider = 
          new LdapAndDatabaseAuthenticationProvider(
              this.ldapAuthenticator(), 
              this.ldapAuthoritiesPopulator(),
              this.personService);
      provider.setUserDetailsContextMapper(userDetailsMapper);
  
      return provider;
    }
  
    @Bean( name = "ldapAuthoritiesPopulator" )
    public LdapAndDatabaseAuthoritiesPopulator ldapAuthoritiesPopulator(){
      return new LdapAndDatabaseAuthoritiesPopulator(this.contextSource(), "", roleService);
    }
  
    @Bean( name = "ldapAuthenticator" )
    public LdapAuthenticator ldapAuthenticator() {
  
        BindAuthenticator authenticator = new BindAuthenticator( this.contextSource() );
        authenticator.setUserDnPatterns(new String[]{"cn={0},ou=prod,o=TEMP"});
  
        return authenticator;
    }
  
    @Bean( name = "contextSource" )
    public DefaultSpringSecurityContextSource contextSource() {
  
        DefaultSpringSecurityContextSource contextSource =
                new DefaultSpringSecurityContextSource( ldapUrl );
        return contextSource;
    }
  
  
  }
  </code></pre>
  
  <p>application.properties:</p>
  
  <pre><code>server.port=8888
  server.context-path=/auth
  security.basic.enabled=false
  </code></pre>
  
  <p>When I login the client application, It correctly forwards to Authorization Server for Single Sign On.
  I enter the user credentials. User successfully get authenticated, but then I see the below error on browser:</p>
  
  <blockquote>
    <p>OAuth Error</p>
    
    <p>error="invalid_grant", error_description="A redirect_uri can only be
    used by implicit or authorization_code grant types."</p>
  </blockquote>
  
  <p>URL Shows:
  <a href="http://localhost:8888/auth/oauth/authorize?client_id=webapp&amp;redirect_uri=http://localhost:8080/jwt/webapp&amp;response_type=code&amp;state=LGvAzj" rel="nofollow noreferrer">http://localhost:8888/auth/oauth/authorize?client_id=webapp&amp;redirect_uri=http://localhost:8080/jwt/webapp&amp;response_type=code&amp;state=LGvAzj</a></p>
  
  <p>I also see the below at the log:</p>
  
  <pre><code>02:14:43.610 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Looking up handler method for path /oauth/authorize 
  02:14:43.614 [http-nio-8888-exec-6] DEBUG o.s.s.o.p.e.FrameworkEndpointHandlerMapping/getHandlerInternal Returning handler method [public org.springframework.web.servlet.ModelAndView  org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map&lt;java.lang.String, java.lang.Object&gt;,java.util.Map&lt;java.lang.String, java.lang.Str ing&gt;,org.springframework.web.bind.support.SessionStatus,java.security.Principal)] 
  02:14:43.849 [http-nio-8888-exec-6] INFO  o.s.s.o.p.e.AuthorizationEndpoint/handleOAuth2Exception Handling OAuth2 error: error="invalid_grant", error_description="A redirect_uri can only be used by implicit or authorization_code grant types."
  </code></pre>
  
  <p>Can you please help me to find the problem?</p>
  
  <p><strong>UPDATE</strong>
  Actually, Dur is right. This configuration is correct and works fine. I had another configuration file which configures JdbcClientDetails and it was overwriting the clientDetailsService created with inmemory in this configuration.</p>