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; } }