0

I have been struggling for days to login and access protected API using OAuth2.0 protocol. I use latest Spring libraries (Spring Security 5). I think I have a problem in Authorization server. So, I will share all codes here:

Configuration File:

@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SecurityFilterChain authSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(httpSecurity);
        return httpSecurity.formLogin(Customizer.withDefaults()).build();
    }

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("client-application")
                .clientSecret(passwordEncoder.encode("secret"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .redirectUri("http://localhost:8000/login/oauth2/code/client-oidc")
                .redirectUri("http://localhost:8000/authorized")
                .scope(OidcScopes.OPENID)
                .scope("READ")
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();

        return new InMemoryRegisteredClientRepository(registeredClient);
    }
    @Bean
    public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
    }

    @Bean
    public JWKSource<SecurityContext> jwkSource() {
        RSAKey rsaKey = generateRsa();
        JWKSet jwkSet = new JWKSet(rsaKey);
        return ((jwkSelector, securityContext) -> jwkSelector.select(jwkSet));
    }
    ...

Another configuration file:

@EnableWebSecurity
public class DefaultSecurityConfig {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean
    @Order
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.cors()
                .and()
                .csrf().disable()
                .headers().frameOptions().sameOrigin()
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests.anyRequest().authenticated()
                )
                .formLogin(Customizer.withDefaults());

        return http.build();
    }

    @Autowired
    public void bindAuthenticationProvider(AuthenticationManagerBuilder authenticationManagerBuilder) {
        authenticationManagerBuilder.authenticationProvider(customAuthenticationProvider);
    }

application.properties:

server:
  port: 9000

And I have a client application:

@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.authorizeRequests(authorizeRequests ->
                        authorizeRequests.anyRequest().authenticated())
                .oauth2Login(oauth2Login ->
                        oauth2Login.loginPage("/oauth2/authorization/client-oidc"))
                .oauth2Client(withDefaults());
        return http.build();
    }
}

application.yml file:

spring:
  security:
    oauth2:
      client:
        registration:
          client-oidc:
            provider: spring
            client-id: client-application
            client-secret: secret
            authorization-grant-type: authorization_code
            redirect-uri: "http://localhost:8000/login/oauth2/code/{registrationId}"
            scope: openid
            client-name: client-oidc
          client-authorization-code:
            provider: spring
            client-id: client-application
            client-secret: secret
            authorization-grant-type: authorization_code
            redirect-uri: "http://localhost:8000/authorized"
            scope: READ
            client-name: client-authorization-code
        provider:
          spring:
            issuer-uri: http://auth-server:9000

I try to access protected API, I am redirected to login page. I enter username and password but in case of error, I go back to login page again. The error is "Access is denied" but I am sure I enter correct information.

Here are the console output:

2022-07-16 22:52:54.487 DEBUG 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Securing GET /articles
2022-07-16 22:52:54.487 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking DisableEncodeUrlFilter (1/16)
2022-07-16 22:52:54.489 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking WebAsyncManagerIntegrationFilter (2/16)
2022-07-16 22:52:54.490 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextPersistenceFilter (3/16)
2022-07-16 22:52:54.490 TRACE 96347 --- [nio-8000-exec-1] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2022-07-16 22:52:54.490 TRACE 96347 --- [nio-8000-exec-1] w.c.HttpSessionSecurityContextRepository : Created SecurityContextImpl [Null authentication]
2022-07-16 22:52:54.491 DEBUG 96347 --- [nio-8000-exec-1] s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
2022-07-16 22:52:54.491 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking HeaderWriterFilter (4/16)
2022-07-16 22:52:54.491 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking CsrfFilter (5/16)
2022-07-16 22:52:54.492 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.csrf.CsrfFilter         : Did not protect against CSRF since request did not match CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
2022-07-16 22:52:54.492 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking LogoutFilter (6/16)
2022-07-16 22:52:54.492 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.logout.LogoutFilter            : Did not match request to Ant [pattern='/logout', POST]
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationRequestRedirectFilter (7/16)
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationRequestRedirectFilter (8/16)
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking OAuth2LoginAuthenticationFilter (9/16)
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking RequestCacheAwareFilter (10/16)
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.s.HttpSessionRequestCache        : No saved request
2022-07-16 22:52:54.493 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking SecurityContextHolderAwareRequestFilter (11/16)
2022-07-16 22:52:54.494 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking AnonymousAuthenticationFilter (12/16)
2022-07-16 22:52:54.497 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
2022-07-16 22:52:54.498 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking OAuth2AuthorizationCodeGrantFilter (13/16)
2022-07-16 22:52:54.499 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking SessionManagementFilter (14/16)
2022-07-16 22:52:54.499 DEBUG 96347 --- [nio-8000-exec-1] o.s.s.w.session.SessionManagementFilter  : Request requested invalid session id E0B30836EC2E93B18880548260904FB0
2022-07-16 22:52:54.499 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking ExceptionTranslationFilter (15/16)
2022-07-16 22:52:54.499 TRACE 96347 --- [nio-8000-exec-1] o.s.security.web.FilterChainProxy        : Invoking FilterSecurityInterceptor (16/16)
2022-07-16 22:52:54.500 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Did not re-authenticate AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] before authorizing
2022-07-16 22:52:54.500 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorizing filter invocation [GET /articles] with attributes [authenticated]
2022-07-16 22:52:54.507 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.expression.WebExpressionVoter  : Voted to deny authorization
2022-07-16 22:52:54.507 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Failed to authorize filter invocation [GET /articles] with attributes [authenticated] using AffirmativeBased [DecisionVoters=[org.springframework.security.web.access.expression.WebExpressionVoter@1e3f0aea], AllowIfAllAbstainDecisions=false]
2022-07-16 22:52:54.512 TRACE 96347 --- [nio-8000-exec-1] o.s.s.w.a.ExceptionTranslationFilter     : Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:73) ~[spring-security-core-5.7.2.jar:5.7.2]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.attemptAuthorization(AbstractSecurityInterceptor.java:239) ~[spring-security-core-5.7.2.jar:5.7.2]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:208) ~[spring-security-core-5.7.2.jar:5.7.2]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:113) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter.doFilterInternal(OAuth2AuthorizationCodeGrantFilter.java:168) ~[spring-security-oauth2-client-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:223) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:178) ~[spring-security-oauth2-client-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter.doFilterInternal(OAuth2AuthorizationRequestRedirectFilter.java:178) ~[spring-security-oauth2-client-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) ~[spring-security-web-5.7.2.jar:5.7.2]
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.21.jar:5.3.21]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.21.jar:5.3.21]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1787) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.64.jar:9.0.64]
    at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]

2022-07-16 22:52:54.536 DEBUG 96347 --- [nio-8000-exec-1] o.s.s.w.s.HttpSessionRequestCache        : Saved request http://localhost:8000/articles to session
2022-07-16 22:52:54.536 DEBUG 96347 --- [nio-8000-exec-1] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://localhost:8000/oauth2/authorization/client-oidc

I was being logged in the past, but I probably changed some parts and now it is broken and I can not fix the error. What might be the cause? Why I am getting "AccessDeniedException"?? From AuthenticationProvider, UsernamePasswordAuthenticationToken is created. Thanks..

Eric
  • 408
  • 8
  • 22

2 Answers2

0

If you intent to correct your Authorization server, change a little bit of your class and method level annotations like below:

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class DefaultSecurityConfig {
    
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE + 1)
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
            throws Exception {
        
        // .........
        
    }
}

It seems every thing looks ok just change SessionCreationPolicy.STATELESS to SessionCreationPolicy.IF_REQUIRED. Because Spring Security creates some session and interact with it. By default, “IF_REQUIRED“.

Run your Server and hit the URL:

http://localhost:9000/oauth2/authorize?client_id=your_client_id&redirect_uri=your_redirect_uri&scope=openid&response_type=code&response_mode=query

Subarata Talukder
  • 5,407
  • 2
  • 34
  • 50
0

Actually, latest spring-security version is 6.0.0 (goes with spring-boot 3).

Be sure to configure your REST API with spring-boot-starter-oauth2-resource-server (not spring-boot-starter-oauth2-client). If you have a doubt, follow those tutorials. It is designed for Keycloak but switching to any other OIDC authorization-server is mostly a matter of editing properties.

If you have server-side rendered UI elements (with Thymeleaf, JSF or whatever) in addition to REST endpoints, create an additional client SecurityFilterChain limited to those UI resources. Spring generated OAuth2 login is part of those UI resources. Be aware that this filter-chain will require sessions (and CSRF protection). Also note that you should use oauth2Login only if you have other server-side rendered UI (rich clients like Angular, React, Vue, Flutter, etc. should use an OIDC client library and handle login & requests authorization by them self). Samples of a second security filter-chain in this answer and that tutorial.

I'd advise you start with a more complete OIDC authorization-server implementation than Spring's one (either on premise like Keycloak or SaaS like Auth0, Okta, Amazon Cognito, and many more). You'll avoid some dangerous miss configurations and save quite some effort: user management screens, registration forms, user database, connectors to LDAP, social login, multi-factor authentication and many more useful features are provided with such solutions and it makes no difference from the resource-server point of view (your REST API).

Edit: disclosure

I am the author of quite a few stackoverflow answers about "OAuth2 spring" and "Keycloak spring" answers (including the one I link here).

I also wrote:

  • the tutorials I link
  • spring-security-test support for OAuth2 (MockMvc post processors and web test client mutator)
  • the support for authentication converter configuration for resource-servers with token introspection in spring-security and Spring-boot
  • a lib with @WithMockUser equivalents for OAuth2 (only annotations enable to test secured with @PreAuthorize and @PostFilter @service and @Repository)
  • thin wrappers arround spring-boot-starter-oauth2-resource-server to move most configuration to properties file (including role mapping and fine grained CORS conf)
ch4mp
  • 6,622
  • 6
  • 29
  • 49
  • When linking to your own site or content (or content that you are affiliated with), you [must disclose your affiliation _in the answer_](/help/promotion) in order for it not to be considered spam. Having the same text in your username as the URL or mentioning it in your profile is not considered sufficient disclosure under Stack Exchange policy. – cigien Dec 11 '22 at 06:57
  • @cigien I noted that answers longer than a comment are rarely upvoted or accepted (read my answers and look at status). What is the value of the disclosure I added to that regard? – ch4mp Dec 11 '22 at 09:29
  • The point of disclosure is to indicate to readers that you as the author have some bias with regards to the quality of the linked material. As far as length of the answers go, you don't have to add an entire section explaining the disclosure. Even something as simple as replacing "this tutorial" with "my tutorial" is sufficient for that particular link, and that doesn't increase the overall length of the answer. Thanks for adding the disclosure though, and make sure to do that on any of your answers that link to your own content. – cigien Dec 11 '22 at 10:18
  • @cigien if you have remarks about the quality of linked content, do not hesitate to open issues, or even better PRs, on the repository those tutorials belong to. I'd be happy to have an opportunity to improve it. – ch4mp Dec 11 '22 at 16:55