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