title: JHipster OAuth2 server - login page for /oauth/authorize
body: <p><strong>tl;dr;</strong></p>
  
  <p>I want to make custom working login page when user is redirected to /oauth/authorize, in <a href="https://jhipster.github.io/" rel="nofollow">jhipster template app</a> I manage to display my login page but it is just redirecting to itself no matter what credentials are used or if I remove </p>
  
  <pre><code>.requestMatchers().antMatchers("/oauth/authorize")
  </code></pre>
  
  <p>from WebSecurityConfigurerAdapter page works fine but /oauth/token returns:</p>
  
  <pre><code>error: "unauthorized"
  error_description: "There is no client authentication. Try adding an appropriate authentication filter."
  </code></pre>
  
  <p><strong>Long description:</strong><br>
  I'm using jhipster template app for resource server with some small admin front end. Except of this I want other client apps to be able to use my resource server, but user login should stay on my app.
  Example Journey:</p>
  
  <ol>
  <li><p>Client app is redirecting user to my app:</p>
  
  <pre><code>127.0.0.1:8080/oauth/authorize?
     response_type=code&amp;client_id=kbExplorer&amp;redirect_uri=http://localhost
  </code></pre></li>
  <li><p>Login page is served for a user</p></li>
  <li>User choose scopes he wants to give</li>
  <li>Server is redirecting to <code>redirect_uri</code> with authorization code</li>
  <li><p>App uses code to get refresh token</p>
  
  <pre><code>127.0.0.1:8080/oauth/token?grand_type=authorization_code&amp;code={code}
  </code></pre></li>
  </ol>
  
  <p>This is typical journey.</p>
  
  <p>Problem starts when I want to change basic http login window, to my own login page.</p>
  
  <p>First thing I've done was changing:</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
  @Order(Ordered.HIGHEST_PRECEDENCE)
  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  
      @Inject
      private UserDetailsService userDetailsService;
  
      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();
      }
  
      @Inject
      public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
          auth
              .userDetailsService(userDetailsService)
                  .passwordEncoder(passwordEncoder());
      }
  
      @Override
      public void configure(WebSecurity web) throws Exception {
          web.ignoring()
              .antMatchers("/scripts/**/*.{js,html}")
              .antMatchers("/bower_components/**")
              .antMatchers("/i18n/**")
              .antMatchers("/assets/**")
              .antMatchers("/swagger-ui/index.html")
              .antMatchers("/api/register")
              .antMatchers("/api/activate")
              .antMatchers("/api/account/reset_password/init")
              .antMatchers("/api/account/reset_password/finish")
              .antMatchers("/test/**")
              .antMatchers("/console/**");
      }
  
      @Override
      public void configure(HttpSecurity http) throws Exception {
          http
                  //.httpBasic().realmName("LES")
                  //.and()
  
                  .requestMatchers().antMatchers("/oauth/authorize")
                  .and()
                  .authorizeRequests()
                  .antMatchers("/api/logput").permitAll()
                  .antMatchers("/oauth/authorize").authenticated()
                  .and()
                  .sessionManagement()
                  .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                  .and()
                  .formLogin().loginPage("/login").permitAll().and().csrf().disable();
      }
  
      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
      }
  
      @Bean
      public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
          return new SecurityEvaluationContextExtension();
      }
  }
  </code></pre>
  
  <p>Thanks to that I'm getting custom login page served from mvc controller:</p>
  
  <pre><code>@Configuration
  public class MvcConfig extends WebMvcConfigurerAdapter {
      @Override
      public void addViewControllers(ViewControllerRegistry registry) {
          registry.addViewController("/login").setViewName("login");
      }
  }
  </code></pre>
  
  <p>But there is a problem right now, when I go to <code>/oauth/authorize</code> login page is served and it is ok, except of whatever you will put there it will always redirect you back to this login page.</p>
  
  <p>I've noticed that if I only remove:</p>
  
  <pre><code>@Override
          public void configure(HttpSecurity http) throws Exception {
              http
                      //.httpBasic().realmName("LES")
                      //.and()
  
                      // This is the line I'm removing:
                      //.requestMatchers().antMatchers("/oauth/authorize")
  
                      //.and()
                      .authorizeRequests()
                      .antMatchers("/api/logput").permitAll()
                      .antMatchers("/oauth/authorize").authenticated()
                      .and()
                      .sessionManagement()
                      .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                      .and()
                      .formLogin().loginPage("/login").permitAll().and().csrf().disable();
          }
  </code></pre>
  
  <p>Whole login works fine. But now admin app stops (this is pure jhipster angularjs template). Just opening this app produces an error:</p>
  
  <pre><code>error: "Internal Server Error"
  exception: "java.lang.IllegalStateException"
  message: "Request processing failed; nested exception is java.lang.IllegalStateException: User not found!"
  path: "/api/account"
  status: 500
  timestamp: "2016-01-22T11:33:08.286+0000"
  </code></pre>
  
  <p>Attempt to log in by default grand_type=password produce:</p>
  
  <pre><code>error: "unauthorized"
  error_description: "There is no client authentication. Try adding an appropriate authentication filter."
  </code></pre>
  
  <p>This is my <code>OAuth2ServerConfiguration</code> (Basically its pure jhipser template):</p>
  
  <pre><code>@Configuration
  public class OAuth2ServerConfiguration {
  
      @Configuration
      @EnableResourceServer
      protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
  
          @Inject
          private Http401UnauthorizedEntryPoint authenticationEntryPoint;
  
          @Inject
          private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;
  
          @Override
          public void configure(HttpSecurity http) throws Exception {
              http
                      .exceptionHandling()
                      .authenticationEntryPoint(authenticationEntryPoint)
                      .and()
                      .logout()
                      .logoutUrl("/api/logout")
                      .logoutSuccessHandler(ajaxLogoutSuccessHandler)
                      .and()
                      .csrf()
                      .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")) // csfr (my own change)
                      .disable()
                      .headers()
                      .frameOptions().disable()
                      .and()
                      .sessionManagement()
                      .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                      .and()
                      .authorizeRequests()
                      .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                      .antMatchers("/api/authenticate").permitAll()
                      .antMatchers("/api/register").permitAll()
                      .antMatchers("/api/logs/**").hasAnyAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/api/**").authenticated()
                      .antMatchers("/metrics/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/health/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/dump/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/shutdown/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/beans/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/configprops/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/info/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/autoconfig/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/env/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/liquibase/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN)
                      .antMatchers("/protected/**").authenticated();
          }
      }
  
      @Configuration
      @EnableAuthorizationServer
      protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
  
          @Inject
          Environment env;
  
          @Inject
          private DataSource dataSource;
  
          @Inject
          private JHipsterProperties jHipsterProperties;
  
          @Bean
          public TokenStore tokenStore() {
              return new JdbcTokenStore(dataSource);
          }
  
          @Inject
          @Qualifier("authenticationManagerBean")
          private AuthenticationManager authenticationManager;
  
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                  throws Exception {
  
              endpoints
                      .tokenStore(tokenStore())
                      .authenticationManager(authenticationManager);
          }
  
          @Override
          public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
              oauthServer.allowFormAuthenticationForClients();
          }
  
          @Override
          public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
              if(env.acceptsProfiles(Constants.SPRING_PROFILE_PRODUCTION)) {
                  clients.jdbc(dataSource);
              }else{
                  clients
                          .jdbc(dataSource)
                          .withClient(jHipsterProperties.getSecurity().getAuthentication().getOauth().getClientid())
                          .scopes("read", "write")
                          .authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
                          .authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
                          .secret(jHipsterProperties.getSecurity().getAuthentication().getOauth().getSecret())
                          .accessTokenValiditySeconds(jHipsterProperties.getSecurity().getAuthentication().getOauth().getTokenValidityInSeconds())
                          .and()
                          .withClient("kbExplorer")
                          .scopes("read", "write")
                          .authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
                          .authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
                          .secret("kbExplorerAppSecret")
                          .accessTokenValiditySeconds(5)
                          .refreshTokenValiditySeconds(1800);
              }
          }
      }
  }
  </code></pre>
  
  <p>Question is:</p>
  
  <p>How to make login page works, without breaking api in same time?</p>