Course – LSS – NPI (cat=Spring Security)
announcement - icon

If you're working on a Spring Security (and especially an OAuth) implementation, definitely have a look at the Learn Spring Security course:


1. Overview

In this quick tutorial, we’ll illustrate how we can revoke tokens granted by an OAuth Authorization Server implemented with Spring Security.

When a user logs out, their token is not immediately removed from the token store; instead, it remains valid until it expires on its own.

And so, revocation of a token will mean removing that token from the token store. We’ll cover the standard token implementation in the framework, not JWT tokens.

Note: this article is using the Spring OAuth legacy project.

2. The TokenStore

First, let’s set up the token store; we’ll use a JdbcTokenStore, along with the accompanying data source:

public TokenStore tokenStore() { 
    return new JdbcTokenStore(dataSource()); 

public DataSource dataSource() { 
    DriverManagerDataSource dataSource =  new DriverManagerDataSource();
    return dataSource;

3. The DefaultTokenServices Bean

The class that handles all tokens is the DefaultTokenServices – and has to be defined as a bean in our configuration:

public DefaultTokenServices tokenServices() {
    DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
    return defaultTokenServices;

4. Displaying the List of Tokens

For admin purposes, let’s also set up a way to view the currently valid tokens.

We’ll access the TokenStore in a controller, and retrieve the currently stored tokens for a specified client id:

TokenStore tokenStore;

@RequestMapping(method = RequestMethod.GET, value = "/tokens")
public List<String> getTokens() {
    List<String> tokenValues = new ArrayList<String>();
    Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientId("sampleClientId"); 
    if (tokens!=null){
        for (OAuth2AccessToken token:tokens){
    return tokenValues;

5. Revoking an Access Token

In order to invalidate a token, we’ll make use of the revokeToken() API from the ConsumerTokenServices interface:

ConsumerTokenServices tokenServices;
@RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
public String revokeToken(@PathVariable String tokenId) {
    return tokenId;

Of course this is a very sensitive operation so we should either only use it internally, or we should take great care to expose it with the proper security in place.

6. The Front-End

For the front-end of our example, we’ll display the list of valid tokens, the token currently used by the logged in user making the revocation request, and a field where the user can enter the token they wish to revoke:

$scope.revokeToken = 
$scope.tokens = $resource("http://localhost:8082/spring-security-oauth-resource/tokens");
$scope.getTokens = function(){
    $scope.tokenList = $scope.tokens.query();	
$scope.revokeAccessToken = function(){
    if ($scope.tokenToRevoke && $scope.tokenToRevoke.length !=0){
        $rootScope.message="Token:"+$scope.tokenToRevoke+" was revoked!";

If a user attempts to use a revoked token again, they will receive an ‘invalid token’ error with status code 401.

7. Revoking the Refresh Token

The refresh token can be used to obtain a new access token. Whenever an access token is revoked, the refresh token that was received with it is invalidated.

If we want to invalidate the refresh token itself also, we can use the method removeRefreshToken() of class JdbcTokenStore, which will remove the refresh token from the store:

@RequestMapping(method = RequestMethod.POST, value = "/tokens/revokeRefreshToken/{tokenId:.*}")
public String revokeRefreshToken(@PathVariable String tokenId) {
    if (tokenStore instanceof JdbcTokenStore){
        ((JdbcTokenStore) tokenStore).removeRefreshToken(tokenId);
    return tokenId;

In order to test that the refresh token is no longer valid after being revoked, we’ll write the following test, in which we obtain an access token, refresh it, then remove the refresh token, and attempt to refresh it again.

We will see that after revocation, we will receive the response error: “invalid refresh token”:

public class TokenRevocationLiveTest {
    private String refreshToken;

    private String obtainAccessToken(String clientId, String username, String password) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("grant_type", "password");
        params.put("client_id", clientId);
        params.put("username", username);
        params.put("password", password);
        Response response = RestAssured.given().auth().
        refreshToken = response.jsonPath().getString("refresh_token");
        return response.jsonPath().getString("access_token");
    private String obtainRefreshToken(String clientId) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("grant_type", "refresh_token");
        params.put("client_id", clientId);
        params.put("refresh_token", refreshToken);
        Response response = RestAssured.given().auth()
        return response.jsonPath().getString("access_token");
    private void authorizeClient(String clientId) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("response_type", "code");
        params.put("client_id", clientId);
        params.put("scope", "read,write");
        Response response = RestAssured.given().auth().preemptive()
    public void givenUser_whenRevokeRefreshToken_thenRefreshTokenInvalidError() {
        String accessToken1 = obtainAccessToken("fooClientIdPassword", "john", "123");
        String accessToken2 = obtainAccessToken("fooClientIdPassword", "tom", "111");
        String accessToken3 = obtainRefreshToken("fooClientIdPassword");
        Response refreshTokenResponse = RestAssured.given().
          header("Authorization", "Bearer " + accessToken3)
        assertEquals(200, refreshTokenResponse.getStatusCode());
        Response revokeRefreshTokenResponse = RestAssured.given()
          .header("Authorization", "Bearer " + accessToken1)
        assertEquals(200, revokeRefreshTokenResponse.getStatusCode());
        String accessToken4 = obtainRefreshToken("fooClientIdPassword");
        Response refreshTokenResponse2 = RestAssured.given()
          .header("Authorization", "Bearer " + accessToken4)
        assertEquals(401, refreshTokenResponse2.getStatusCode());

8. Conclusion

In this tutorial, we have demonstrated how to revoke an OAuth access token and an Oauth refresh token.

The implementation of this tutorial can be found in the GitHub project.

Course – LSS (cat=Security/Spring Security)

I just announced the new Learn Spring Security course, including the full material focused on the new OAuth2 stack in Spring Security:

res – Security (video) (cat=Security/Spring Security)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.