Programmatically removing authentication by invalidating token | Spring OAuth2

It’s a pain revoking user authentication (Logging out a user) programmatically in spring oauth2. Specially if we use in memory token store.

But it’s pretty easy to do that if we look into it. Let’s demonstrate how we can invalidate a token for a specific user.

1. Create new access token for a user

    public OAuth2AccessToken createAccessToken(User user) {

        Map<String, String> requestParameters = new HashMap<>();
        Set<String> scope = new HashSet<>();
        scope.add("read write trust");
        Set<String> resourceIds = new HashSet<>();
        Set<String> responseTypes = new HashSet<>();
        responseTypes.add("code");
        Map<String, Serializable> extensionProperties = new HashMap<>();

        OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, this.clientId,
                user.getAuthorities(), user.isEnabled(), scope,
                resourceIds, null, responseTypes, extensionProperties);


        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
        AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();
        return tokenService.createAccessToken(auth);
    }

2. Get access token for a user

public OAuth2AccessToken getAccessToken(String username) {
        Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientIdAndUserName(clientId, username);
        if (tokens != null && !tokens.isEmpty())
            return getLastElement(tokens);
        return null;
}
    
public static <T> T getLastElement(final Iterable<T> elements) {
    final Iterator<T> itr = elements.iterator();
    T lastElement = itr.next();

    while (itr.hasNext()) {
        lastElement = itr.next();
    }

    return lastElement;
}

 

3. Revoke Token/Remove authentication

private boolean revokeToken(String tokenValue) {
    OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
    if (accessToken == null) {
        return false;
    }
    if (accessToken.getRefreshToken() != null) {
        tokenStore.removeRefreshToken(accessToken.getRefreshToken());
    }
    tokenStore.removeAccessToken(accessToken);
    return true;
}

public void revokeAuthentication(User user) {
    Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientIdAndUserName(clientId, user.getUsername());
    for (OAuth2AccessToken token : tokens) {
        revokeToken(token.getValue());
    }
}

Full @Service class should be like

@Service
public class TokenService {
    private final TokenStore tokenStore;
    private final AuthorizationServerEndpointsConfiguration configuration;
    @Value("${app.client.id}")
    private String clientId;

    @Autowired
    public TokenService(@Qualifier("inMemoryTokenStore") TokenStore tokenStore, AuthorizationServerEndpointsConfiguration configuration) {
        this.tokenStore = tokenStore;
        this.configuration = configuration;
    }

    public void revokeAuthentication(User user) {
        Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientIdAndUserName(clientId, user.getUsername());
        for (OAuth2AccessToken token : tokens) {
            revokeToken(token.getValue());
        }
    }

    public OAuth2AccessToken createAccessToken(User user) {

        Map<String, String> requestParameters = new HashMap<>();
        Set<String> scope = new HashSet<>();
        scope.add("read write trust");
        Set<String> resourceIds = new HashSet<>();
        Set<String> responseTypes = new HashSet<>();
        responseTypes.add("code");
        Map<String, Serializable> extensionProperties = new HashMap<>();

        OAuth2Request oAuth2Request = new OAuth2Request(requestParameters, this.clientId,
                user.getAuthorities(), user.isEnabled(), scope,
                resourceIds, null, responseTypes, extensionProperties);


        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        OAuth2Authentication auth = new OAuth2Authentication(oAuth2Request, authenticationToken);
        AuthorizationServerTokenServices tokenService = configuration.getEndpointsConfigurer().getTokenServices();
        return tokenService.createAccessToken(auth);
    }

    public OAuth2AccessToken getAccessToken(String username) {
        Collection<OAuth2AccessToken> tokens = tokenStore.findTokensByClientIdAndUserName(clientId, username);
        if (tokens != null && !tokens.isEmpty())
            return Commons.getLastElement(tokens);
        return null;
    }

    private boolean revokeToken(String tokenValue) {
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
        if (accessToken == null) {
            return false;
        }
        if (accessToken.getRefreshToken() != null) {
            tokenStore.removeRefreshToken(accessToken.getRefreshToken());
        }
        tokenStore.removeAccessToken(accessToken);
        return true;
    }

}

 

Leave a Reply

Your email address will not be published. Required fields are marked *