title: Spring Boot OAuth 2 - expiring refresh tokens when password changed
body: <p>I've created an API using Spring Boot/OAuth. It's currently set so that access_tokens are valid for 30 days, and refresh_tokens are valid for 5 years. It's been requested that OAuth work this way so that a single refresh_token can be used over and over again. What we also need to do is implement some way of expiring refresh tokens when a user changes their password, this is what I'm struggling with as we're not using a token store as we're using JWTs, so there's no need to store the tokens, and even when we were storing that in a database we regularly got 'Invalid refresh token' errors, so removed the token store.</p>
  
  <p>My question is, how to you handle expiring refresh tokens, say, when a user changes their password (as suggested by OAuth).</p>
  
  <p>My client has specifically requested that the returned refresh_token be long-life, but I'm concerned that a long-life refresh token isn't very secure, as if anyone gets hold of that token they can access the users account until that token naturally expires. Personally I'd prefer to set a shorter expiry on refresh_tokens at say 45 days, forcing the client to store a new refresh_token every 45 days at least.</p>
  
  <p>Here's are some of my configuration classes for security to show how I currently have things setup;</p>
  
  <pre><code>@Configuration
  @EnableWebSecurity
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  
      @Autowired
      private Environment env;
  
      @Autowired
      private CustomUserDetailsService userDetailsService;
  
      @Autowired
      private AccountAuthenticationProvider accountAuthenticationProvider;
  
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.userDetailsService(userDetailsService);
          auth.authenticationProvider(accountAuthenticationProvider);
      }
  
      @Bean
      public PasswordEncoder passwordEncoder() {
          return new BCryptPasswordEncoder();
      }
  
      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
          return super.authenticationManagerBean();
      }
  
      @Bean
      public JwtAccessTokenConverter jwtAccessTokenConverter() {
          final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
          jwtAccessTokenConverter.setSigningKey(env.getProperty("jwt.secret"));
          return jwtAccessTokenConverter;
      }
  
  }
  
  
  
  @Configuration
  public class OAuth2ServerConfiguration {
  
      private static final String RESOURCE_ID = "myapi";
  
      @Autowired
      DataSource dataSource;
  
      @Bean
      public TokenStore tokenStore() {
          return new JdbcTokenStore(dataSource);
      }
  
      @Configuration
      @EnableResourceServer
      protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
  
          @Autowired
          TokenStore tokenStore;
  
          @Override
          public void configure(ResourceServerSecurityConfigurer resources) {
              resources
                      .resourceId(RESOURCE_ID)
                      .tokenStore(tokenStore);
          }
  
          @Override
          public void configure(HttpSecurity http) throws Exception {
              http
                      .csrf().disable()
                      .authorizeRequests()
                      .antMatchers("/oauth/**", "/view/**").permitAll()
                      .anyRequest().authenticated();
          }
      }
  
      @Configuration
      @EnableAuthorizationServer
      protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
          @Autowired
          private JwtAccessTokenConverter jwtAccessTokenConverter;
  
          @Autowired
          private DataSource dataSource;
  
          @Autowired
          private TokenStore tokenStore;
  
          @Autowired
          private CustomUserDetailsService userDetailsService;
  
          @Autowired
          @Qualifier("authenticationManagerBean")
          private AuthenticationManager authenticationManager;
  
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
              endpoints
                      //.tokenStore(tokenStore)
                      .authenticationManager(authenticationManager)
                      .userDetailsService(userDetailsService)
                      .accessTokenConverter(jwtAccessTokenConverter);
          }
  
          @Override
          public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
              clients
                      .jdbc(dataSource);
          }
      }
  
  }
  </code></pre>