title: How to overcome intermittent Scope 'session' is not active for the current thread for OauthClientContext?
body: <p>I'm attempting to implement OpenId Connect sign-on in a Spring Boot 1.3.0 application with Spring Security 3.2.5 on Spring Framework 4.2.3. The implementation is very similar to this question: <a href="https://stackoverflow.com/q/35875098/1146608">Protecting REST API with OAuth2: Error creating bean with name &#39;scopedTarget.oauth2ClientContext&#39;: Scope &#39;session&#39; is not active</a>, except that I've implemented the suggested bean for the <code>RequestContextFilter</code>.</p>
  
  <pre><code>@Configuration
  @EnableOAuth2Client
  public class OpenIdConnectConfig {
      @Value("${oidc.clientId}")
      private String clientId;
  
      @Value("${oidc.clientSecret}")
      private String clientSecret;
  
      @Value("${oidc.accessTokenUrl}")
      private String accessTokenUri;
  
      @Value("${oidc.userAuthorizationUri}")
      private String userAuthorizationUri;
  
      @Value("${oidc.redirectUri}")
      private String redirectUri;
  
      @Value("#{'${oidc.scopes}'.split(',')}")
      private List&lt;String&gt; oidcScopes;
  
      @Bean
      public OAuth2ProtectedResourceDetails openIdResourceDetails() {
          AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
          details.setClientId(clientId);
          details.setClientSecret(clientSecret);
          details.setAccessTokenUri(accessTokenUri);
          details.setUserAuthorizationUri(userAuthorizationUri);
          details.setClientAuthenticationScheme(AuthenticationScheme.form);
          details.setScope(oidcScopes);
          details.setPreEstablishedRedirectUri(redirectUri);
          details.setUseCurrentUri(false);
          return details;
      }
  
      @Bean(name = "my.company.ui.security.OpenIdRestTemplate")
      // ToDo: fix org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.oauth2ClientContext': Scope 'session' is not active for the current thread
      public OAuth2RestTemplate OpenIdRestTemplate(OAuth2ClientContext clientContext) {
          return new OAuth2RestTemplate(openIdResourceDetails(), clientContext);
      }
  
      @Bean
      public RequestContextListener requestContextListener() {
          return new RequestContextListener();
      }
  }
  </code></pre>
  
  <p>The exception stack trace is likewise similar</p>
  
  <pre><code>Caused by:
  org.springframework.beans.factory.BeanCreationException: 
    Error creating bean with name 'scopedTarget.oauth2ClientContext':
    Scope 'session' is not active for the current thread; consider 
    defining a scoped proxy for this bean if you intend to refer to it
    from a singleton; 
  nested exception is java.lang.IllegalStateException: No thread-bound
    request found: Are you referring to request attributes outside of an
    actual web request, or processing a request outside of the originally 
    receiving thread? If you are actually operating within a web request
    and still receive this message, your code is probably running outside 
    of DispatcherServlet/DispatcherPortlet: In this case, use 
    RequestContextListener or RequestContextFilter to expose the current request.
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:355)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
      at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
      at com.sun.proxy.$Proxy78.getAccessToken(Unknown Source)
      at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
      at my.company.ui.security.OpenIdConnectFilter.attemptAuthentication(OpenIdConnectFilter.java:118)
      at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
      at my.company.ui.security.OpenIdConnectFilter.doFilter(OpenIdConnectFilter.java:93)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
      at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at my.company.ui.security.UserCookieFilter.doFilter(UserCookieFilter.java:29)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at my.company.server.filter.UncaughtExceptionRequestFilter.doFilter(UncaughtExceptionRequestFilter.java:45)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at com.rmn.commons.web.metrics.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:143)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:167)
      at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
      at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
      at org.eclipse.jetty.server.Server.handle(Server.java:499)
      at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
      at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
      at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
      at java.lang.Thread.run(Thread.java:748)
  Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
      at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
      at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
      ... 48 more
  Caused by:
  java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
      at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
      at org.springframework.web.context.request.SessionScope.get(SessionScope.java:91)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:340)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
      at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
      at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
      at com.sun.proxy.$Proxy78.getAccessToken(Unknown Source)
      at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:169)
      at my.company.ui.security.OpenIdConnectFilter.attemptAuthentication(OpenIdConnectFilter.java:118)
      at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211)
      at my.company.ui.security.OpenIdConnectFilter.doFilter(OpenIdConnectFilter.java:93)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
      at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
      at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
      at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
      at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at my.company.ui.security.UserCookieFilter.doFilter(UserCookieFilter.java:29)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at my.company.server.filter.UncaughtExceptionRequestFilter.doFilter(UncaughtExceptionRequestFilter.java:45)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at com.rmn.commons.web.metrics.AbstractInstrumentedFilter.doFilter(AbstractInstrumentedFilter.java:143)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:167)
      at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80)
      at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
      at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
      at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
      at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
      at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
      at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
      at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
      at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
      at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
      at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:215)
      at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
      at org.eclipse.jetty.server.Server.handle(Server.java:499)
      at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
      at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
      at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
      at java.lang.Thread.run(Thread.java:748)
  Powered by Jetty://
  </code></pre>
  
  <p>You can clearly see that the filter call is part of the Spring Security <code>FilterChainProxy</code>, so I don't know what to make of the error message's suggestion that "your code is probably running outside of DispatcherServlet/DispatcherPortlet". Also, I have tried adding a bean for the suggested alternative <code>RequestContextFilter</code> and the same exception is thrown.</p>
  
  <p>The filter that performs the authentication (some exception handling and user processing code removed):</p>
  
  <pre><code>public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
  
      public OpenIdConnectFilter(
              RequestMatcher requiresAuthenticationRequestMatcher,
              AuthenticationService authenticationService
      ) {
          super(requiresAuthenticationRequestMatcher);
          setAuthenticationManager(new NoopAuthenticationManager());
      }
  
      @SuppressWarnings("RedundantThrows") // Matching overridden method
      @Override
      public Authentication attemptAuthentication(
              HttpServletRequest request,
              HttpServletResponse response
      ) throws AuthenticationException, IOException, ServletException {
  
          // Required parameters (one-time access code, state) are retrieved from the context
          OAuth2AccessToken oAuth2AccessToken = restTemplate.getAccessToken();
  
          // Process the token, get the user details, return an Authentication object.
      }
  
      public void setRestTemplate(OAuth2RestTemplate restTemplate) {
          this.restTemplate = restTemplate;
  
      }
  
      private static class NoopAuthenticationManager implements AuthenticationManager {
  
          @Override
          public Authentication authenticate(Authentication authentication) throws AuthenticationException {
              throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
          }
  
      }
  
  
      private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdConnectFilter.class);
  
      @Value("${oidc.clientId}")
      private String clientId;
  
      @Value("${oidc.issuer}")
      private String issuer;
  
      @Value("${oidc.jwt.jwk.url}")
      private String jwkUrl;
  
      private final AuthenticationService authenticationService;
  
      private OAuth2RestTemplate restTemplate;
  }
  </code></pre>
  
  <p>And the Security Config that sets up the Spring Security FilterProxyChain:</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableOAuth2Client
  public class SecurityConfig extends WebSecurityConfigurerAdapter{
  
      @Override
      @SuppressWarnings("unchecked")
      protected void configure(HttpSecurity http)
              throws Exception {
  
          http
              .sessionManagement()
                  .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
              .and()
              .csrf()
                  .disable()
              .authorizeRequests()
                  .expressionHandler(securityExpressionHandler)
                  .antMatchers("/asset/**").access("permitAll")
                  .antMatchers("/ws/ssoEnabled").access("permitAll")
                  .antMatchers("/**").access("hasRole('ROLE_USER') or hasRole('ROLE_TOKEN_ACCESS')")
                  .and()
              .httpBasic()
                  .authenticationEntryPoint(ajaxAwareLoginUrlAuthenticationEntryPoint)
                  .and()
              // Handles unauthenticated requests, catching UserRedirectRequiredExceptions and redirecting to OAuth provider
              .addFilterAfter(new OAuth2ClientContextFilter(), SecurityContextPersistenceFilter.class)
              // Handles the oauth callback, exchanging the one-time code for a durable token
              .addFilterAfter(openIdConnectFilter, OAuth2ClientContextFilter.class)
              .formLogin()
                  .loginPage("/login")
                  .loginProcessingUrl("/logincheck")
                  .usernameParameter("username")
                  .passwordParameter("password")
                  .successHandler(ajaxAwareAuthenticationSuccessHandler)
                  .failureHandler(ajaxAwareAuthenticationFailureHandler)
                  .and()
              .logout()
                  .logoutUrl("/logout")
                  .logoutSuccessUrl("/login")
                  .and()
              .rememberMe()
                  .rememberMeServices(rememberMeServices)
                  // Even though this key has been added directly to the rememberMeServices instance, the RememberMeConfigurer
                  // can instantiate a new RememberMeServices with a made-up key if the same key is not provided.
                  .key("the key value")
          ;
  
          // We do not configure a bean for the SessionAuthenticationStrategy. We want to use the Spring default strategy,
          // which is configured by the above builder chain. In order to share the correct, configured instance with our
          // custom OpenIdConnectFilter, we first tell the builder to perform the configuration (normally this would be
          // done long after this method returns)...
          http.getConfigurer(SessionManagementConfigurer.class).init(http);
          // ... then we get the shared object by interface (SessionAuthenticationStrategy) class name...
          final SessionAuthenticationStrategy sessionAuthenticationStrategy = http.getSharedObject(SessionAuthenticationStrategy.class);
          // ... then set it in our custom filter.
          openIdConnectFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
      }
  }
  </code></pre>
  
  <p>One final wrinkle: I was getting this error while running on my machine. Then, adding the <code>RequestContextListener</code> resolved it. When deploying it to our test environment, the exception message resurfaces. However, after a few hours or days, sometimes after the CI/CD pipeline re-deploys the same version, the problem resolves itself and the OpenID integration works as expected until we make the next change, bugfix or improvement, then it usually reoccurs for a similar short interval.</p>
  
  <hr>
  
  <p>Questions:</p>
  
  <ol>
  <li>Is <code>DispatcherServlet/DispatcherPortlet</code> a factor at all when running in Spring Boot?</li>
  <li>How do you determine if you should use a <a href="https://docs.spring.io/spring-framework/docs/4.2.3.RELEASE/javadoc-api/org/springframework/web/filter/RequestContextFilter.html" rel="nofollow noreferrer"><code>RequestContextFilter</code></a> or <a href="https://docs.spring.io/spring-framework/docs/4.2.3.RELEASE/javadoc-api/org/springframework/web/context/request/RequestContextListener.html" rel="nofollow noreferrer"><code>RequestContextListener</code></a>? Is there an actual difference? The (linked) documentation isn't much help here, in my opinion.
  
  <blockquote>
    <p>Servlet listener that exposes the request to the current thread, through both LocaleContextHolder and RequestContextHolder. To be registered as listener in web.xml.</p>
    
    <p>Alternatively, Spring's RequestContextFilter and Spring's DispatcherServlet also expose the same request context to the current thread. In contrast to this listener, advanced options are available there (e.g. "threadContextInheritable").</p>
    
    <p>This listener is mainly for use with third-party servlets, e.g. the JSF FacesServlet. Within Spring's own web support, DispatcherServlet's processing is perfectly sufficient.</p>
  </blockquote></li>
  <li>Where should the Beans for the RequestContextFilter/Listener be defined in a Spring Boot app? We don't have a <code>web.xml</code>. (My understanding is that <code>web.xml</code> is only for Spring MVC - please correct me if that is wrong.)</li>
  <li>What could possibly be causing the context to be found <em>sometimes</em>? Why is it that our app can work after enduring failure for a little while?</li>
  </ol>