title: Migrating away from Spring Security OAuth 2
body: <p>I'm having a Spring Boot Auth Microservice. It uses the Oauth2 spring cloud starter dependency which is <a href="https://spring.io/blog/2019/11/14/spring-security-oauth-2-0-roadmap-update" rel="nofollow noreferrer">deprecated nowadays</a>.</p>
  <pre><code>buildscript {
    dependencies {
      classpath &quot;org.springframework.boot:spring-boot-gradle-plugin:2.1.9.RELEASE&quot;
    }
  }
  
  dependencies {
    implementation &quot;org.springframework.boot:spring-boot-starter-actuator&quot;
    implementation &quot;org.springframework.boot:spring-boot-starter-data-jpa&quot;
    implementation &quot;org.springframework.boot:spring-boot-starter-web&quot;
    implementation &quot;org.springframework.cloud:spring-cloud-starter-oauth2:2.1.5.RELEASE&quot;
  }
  </code></pre>
  <p>The Schema was taken from here: <a href="https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql" rel="nofollow noreferrer">https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql</a></p>
  <p>It also has a custom <code>user_details</code> table. The JPA class is implementing <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/userdetails/UserDetails.html" rel="nofollow noreferrer"><code>UserDetails</code></a>. I've also provided an implementation for <a href="https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/index.html?org/springframework/security/core/userdetails/UserDetailsService.html" rel="nofollow noreferrer"><code>UserDetailsService</code></a> which looks up the user in my custom table.</p>
  <p>OAuth Configuration is quite forward:</p>
  <p><strong>AuthorizationServerConfiguration</strong> - where oauth is configured:</p>
  <pre><code>@Configuration
  @EnableGlobalMethodSecurity(prePostEnabled = true)
  @EnableAuthorizationServer
  class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() {
      @Autowired private lateinit var authenticationManager: AuthenticationManager
      @Autowired private lateinit var dataSource: DataSource
  
      @Autowired
      @Qualifier(&quot;customUserDetailsService&quot;)
      internal lateinit var userDetailsService: UserDetailsService
  
      @Autowired
      private lateinit var passwordEncoder: BCryptPasswordEncoder
  
      override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
          endpoints
                  .tokenStore(JdbcTokenStore(dataSource))
                  .authenticationManager(authenticationManager)
                  .userDetailsService(userDetailsService)
      }
  
      override fun configure(clients: ClientDetailsServiceConfigurer) {
          // This one is used in conjunction with oauth_client_details. So like there's one app client and a few backend clients.
          clients.jdbc(dataSource)
      }
  
      override fun configure(oauthServer: AuthorizationServerSecurityConfigurer) {
          oauthServer.passwordEncoder(passwordEncoder)
      }
  }
  </code></pre>
  <p><strong>WebSecurityConfiguration</strong> - needed for class above:</p>
  <pre><code>@Configuration
  class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {
    @Bean // We need this as a Bean. Otherwise the entire OAuth service won't work.
    override fun authenticationManagerBean(): AuthenticationManager {
      return super.authenticationManagerBean()
    }
  
    override fun configure(http: HttpSecurity) {
      http.sessionManagement()
          .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    }
  }
  </code></pre>
  <p><strong>ResourceServerConfiguration</strong> - to configure access for endpoints:</p>
  <pre><code>@Configuration
  @EnableResourceServer
  class ResourceServerConfiguration : ResourceServerConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
      http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
          .and().cors().disable().csrf().disable()
          .authorizeRequests()
  
          .antMatchers(&quot;/oauth/token&quot;).authenticated()
          .antMatchers(&quot;/oauth/user/**&quot;).authenticated()
  
          .antMatchers(&quot;/oauth/custom_end_points/**&quot;).hasAuthority(&quot;my-authority&quot;)
  
          // Deny everything else.
          .anyRequest().denyAll()
    }
  }
  </code></pre>
  <p>These few lines give me a lot.</p>
  <ul>
  <li>User Info endpoint (used by microservices)</li>
  <li>Client's such as Mobile frontends can authenticate using: <code>POST oauth/token</code> and providing a <code>grant_type=password</code> together with a username and a password.</li>
  <li>Servers can authorize using 'oauth/authorize'</li>
  <li>Basic Auth support with different authorities is also available as I can fill username + password into the <code>oauth_client_details</code> table:</li>
  </ul>
  <pre><code>select client_id, access_token_validity, authorities, authorized_grant_types, refresh_token_validity, scope from oauth_client_details;
       client_id     | access_token_validity |          authorities          |          authorized_grant_types           | refresh_token_validity |  scope
  -------------------+-----------------------+-------------------------------+-------------------------------------------+------------------------+---------
   backend           |                864000 | mail,push,app-register        | mail,push,client_credentials              |                 864000 | backend
   app               |                864000 | grant                         | client_credentials,password,refresh_token |                      0 | app
  </code></pre>
  <p>This is used by the app if there's no oauth token yet.</p>
  <p>Other microservices also use this to protect their endpoints - such as in this example:</p>
  <pre><code>@Configuration @EnableResourceServer class ResourceServerConfig : ResourceServerConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
      http.authorizeRequests()
          // Coach.
          .antMatchers(&quot;/api/my-api/**&quot;).hasRole(&quot;my-role&quot;)
          .antMatchers(&quot;/registration/**&quot;).hasAuthority(&quot;my-authority&quot;)
    }
  }
  </code></pre>
  <p>Their set up is quite easy:</p>
  <pre><code>security.oauth2.client.accessTokenUri=http://localhost:20200/oauth/token
  security.oauth2.client.userAuthorizationUri=http://localhost:20200/oauth/authorize
  security.oauth2.resource.userInfoUri=http://localhost:20200/oauth/user/me
  security.oauth2.client.clientId=coach_client
  security.oauth2.client.clientSecret=coach_client
  </code></pre>
  <p>The first three properties just go to my authorization server. The last two properties are the actual username + password that I've also inserted inside the <code>oauth_client_details</code> table. When my microservice wants to talk to another microservice it uses:</p>
  <pre><code>val details = ClientCredentialsResourceDetails()
  details.clientId = &quot;&quot; // Values from the properties file.
  details.clientSecret = &quot;&quot; // Values from the properties file.
  details.accessTokenUri = &quot;&quot; // Values from the properties file.
  val template = OAuth2RestTemplate(details)
  template.exchange(...)
  </code></pre>
  <p>Now my question is - how can I get all of this with the built in Support from Spring Security using Spring Boot? I'd like to migrate away from the deprecated packages and retain all tokens so that users are still logged in afterwards.</p>