title: TokenStore in Spring Security 5.x after removal of Spring Security OAuth 2.x
body: <p>Are there plans to provide TokenStore in Spring Security 5.x after end of life of Spring Security OAuth 2.x?
  Currently we are using JdbcTokenStore to cache the tokens, which later on are used to accomplish long running processes on behalf of the user.</p>
  <p>Here is the current application setup:</p>
  <ul>
  <li>App is running on several instances in Cloud Foundry</li>
  <li>App uses postgre as backing service</li>
  <li>App receives oauth tokens</li>
  <li>App acts on behalf of the user, by using the tokens, to call Cloud Controller. Actual computing and external calls can be done on different app instances.</li>
  </ul>
  <p>The current flow regarding the tokens is:</p>
  <ol>
  <li><p>App clients call some of the app instances and trigger long running process, let's say app instance #0 is called. Oauth token is provided in the API call.</p>
  </li>
  <li><p>Custom filter (before=&quot;PRE_AUTH_FILTER&quot;) on #0 stores the token in JdbcTokenStore.
  <a href="https://github.com/cloudfoundry-incubator/multiapps-controller/blob/master/multiapps-controller-web/src/main/resources/security-context.xml#L49" rel="nofollow noreferrer">security-context.xml</a></p>
  <pre><code>&lt;sec:custom-filter ref=&quot;resourceServerFilter&quot; before=&quot;PRE_AUTH_FILTER&quot; /&gt;
  ....
  &lt;oauth:resource-server id=&quot;resourceServerFilter&quot; resource-id=&quot;springsec&quot;
  token-services-ref=&quot;customTokenServices&quot; /&gt;
  </code></pre>
  </li>
  </ol>
  <p><a href="https://github.com/cloudfoundry-incubator/multiapps-controller/blob/master/multiapps-controller-web/src/main/java/org/cloudfoundry/multiapps/controller/web/security/CustomTokenServices.java" rel="nofollow noreferrer">CustomTokenServices</a></p>
  <pre><code>@Override
  public OAuth2Authentication loadAuthentication(String tokenString) {
  
      // Get an access token for the specified token string
      OAuth2AccessToken token = readAccessToken(tokenString);
  
      // Check if a valid access token has been obtained
      if (token == null) {
          logToAuditLogAndThrow(&quot;Invalid access token&quot;);
      }
  
      // Check if the token has expired and there is no refresh token
      if (token.isExpired() &amp;&amp; token.getRefreshToken() == null) {
          tokenStore.removeAccessToken(token);
          logToAuditLogAndThrow(MessageFormat.format(&quot;The access token has expired on {0}&quot;, token.getExpiration()));
      }
  
      // Check if an authentication for this token already exists in the token store
      OAuth2Authentication auth = tokenStore.readAuthentication(token);
      if (auth == null) {
          // Create an authentication for the token and store it in the token store
          TokenProperties tokenProperties = TokenProperties.fromToken(token);
          auth = SecurityUtil.createAuthentication(tokenProperties.getClientId(), token.getScope(), SecurityUtil.getTokenUserInfo(token));
          try {
              LOGGER.info(MessageFormat.format(Messages.STORING_TOKEN_FOR_USER_0_WITH_EXPIRATION_TIME_1, tokenProperties.getUserName(),
                                               token.getExpiresIn()));
              tokenStore.storeAccessToken(token, auth);
          } catch (DataIntegrityViolationException e) {
              LOGGER.debug(Messages.ERROR_STORING_TOKEN_DUE_TO_INTEGRITY_VIOLATION, e);
              // Ignoring the exception as the token and authentication are already persisted by another client.
          }
      }
  
      return auth;
  }
  
  @Override
  public OAuth2AccessToken readAccessToken(String tokenString) {
      // Check if an access token for the received token string already exists in the token store
      OAuth2AccessToken token = tokenStore.readAccessToken(tokenString);
      if (token != null) {
          LOGGER.debug(&quot;Stored token value: &quot; + token.getValue());
          LOGGER.debug(&quot;Stored token type: &quot; + token.getTokenType());
          LOGGER.debug(&quot;Stored token expires in: &quot; + token.getExpiresIn());
      } else {
          token = tokenParserChain.parse(tokenString);
      }
      return token;
  }
  </code></pre>
  <ol start="3">
  <li><p>Custom filter (position=&quot;LAST&quot;) on #0, reads the token from JdbcToken store and performs some basic validations, such as expiration time, desired scopes and so on. If everything is ok, continue.
  <a href="https://github.com/cloudfoundry-incubator/multiapps-controller/blob/master/multiapps-controller-web/src/main/resources/security-context.xml#L49" rel="nofollow noreferrer">security-context.xml</a></p>
  <pre><code>&lt;sec:custom-filter ref=&quot;compositeUriAuthorizationFilter&quot; position=&quot;LAST&quot; /&gt;
  </code></pre>
  </li>
  <li><p>Actual execution of the long process starts, where it is split in smaller processing steps. Each processing step can be executed on different app instance depending on the load. The esential thing is that everything is stored in DB which serves as single source of truth. <strong>NOTE</strong> Next steps describe basically what one step does</p>
  </li>
  <li><p>Processing step starts, let's say on app instance #1. App searches
  and finds tokens in JdbcTokenStore by user, who started the process. The token that has largest expiration time is get</p>
  </li>
  </ol>
  <p><a href="https://github.com/cloudfoundry-incubator/multiapps-controller/blob/master/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/security/token/TokenService.java" rel="nofollow noreferrer">TokenService</a></p>
  <pre><code>public OAuth2AccessToken getToken(String userName) {
          OAuth2AccessToken token = null;
          Collection&lt;OAuth2AccessToken&gt; tokens = tokenStore.findTokensByUserName(userName);
          for (OAuth2AccessToken tokenx : tokens) {
              // If a token is already found, overwrite it if the new token:
              // 1) has a refresh token, and the current token hasn't, or
              // 2) expires later than the current token
              if (token == null || ((tokenx.getRefreshToken() != null) &amp;&amp; (token.getRefreshToken() == null))
                  || (tokenx.getExpiresIn() &gt; token.getExpiresIn())) {
                  token = tokenx;
              }
          }
          return token;
      }
  </code></pre>
  <ol start="6">
  <li>The token is used for next external calls to Cloud Controller.</li>
  </ol>
  <p><a href="https://github.com/cloudfoundry-incubator/multiapps-controller/blob/master/multiapps-controller-core/src/main/java/org/cloudfoundry/multiapps/controller/core/cf/CloudControllerClientProvider.java" rel="nofollow noreferrer">CloudControllerClientProvider</a></p>
  <pre><code>private OAuth2AccessToken getValidToken(String userName) {
          OAuth2AccessToken token = tokenService.getToken(userName);
          if (token == null) {
              throw new SLException(Messages.NO_VALID_TOKEN_FOUND, userName);
          }
  
          if (token.isExpired() &amp;&amp; token.getRefreshToken() == null) {
              tokenService.removeToken(token);
              throw new SLException(Messages.TOKEN_EXPIRED, userName);
          }
  
          return token;
      }
  ...
  public CloudControllerClient getControllerClient(String userName) {
          try {
              return clientFactory.createClient(getValidToken(userName));
          } catch (CloudOperationException e) {
              throw new SLException(e, Messages.CANT_CREATE_CLIENT);
          }
      }
  </code></pre>
  <p>Best Regards,
  Boyan</p>