3.2.15. Token revocation
Sometimes, you may want to revoke the current authorization code flow access and/or refresh tokens. You can revoke tokens with quarkus.oidc.OidcProviderClient which provides access to the OIDC provider’s UserInfo, token introspection and revocation endpoints.
For example, when a local logout with OidcSession is performed, you can use an injected OidcProviderClient to revoke access and refresh tokens associated with the current session:
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.OidcProviderClient;
import io.quarkus.oidc.OidcSession;
import io.quarkus.oidc.RefreshToken;
import io.smallrye.mutiny.Uni;
@Path("/service")
public class ServiceResource {
@Inject
OidcSession oidcSession;
@Inject
OidcProviderClient oidcProviderClient;
@Inject
AccessTokenCredential accessToken;
@Inject
RefreshToken refreshToken;
@GET
public Uni<String> logout() {
return oidcSession.logout()
.chain(() -> oidcClient.revokeAccessToken(accessToken.getToken()))
.chain(() -> oidcClient.revokeRefreshToken(refreshToken.getToken()))
.map((result) -> "You are logged out");
}
}
You can also revoke tokens in the security event listeners.
For example, when your application supports a standard User-initiated logout, you can catch a logout event and revoke tokens:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import io.quarkus.oidc.AccessTokenCredential;
import io.quarkus.oidc.OidcProviderClient;
import io.quarkus.oidc.RefreshToken;
import io.quarkus.oidc.SecurityEvent;
import io.quarkus.security.identity.SecurityIdentity;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.ObservesAsync;
@ApplicationScoped
public class SecurityEventListener {
public CompletionStage<Void> processSecurityEvent(@ObservesAsync SecurityEvent event) {
if (SecurityEvent.Type.OIDC_LOGOUT_RP_INITIATED == event.getEventType()) {
return revokeTokens(event.getSecurityIdentity()).subscribeAsCompletionStage();
}
return CompletableFuture.completedFuture(null);
}
private Uni<Void> revokeTokens(SecurityIdentity securityIdentity) {
return Uni.join().all(
revokeAccessToken(securityIdentity),
revokeRefreshToken(securityIdentity)
).andCollectFailures()
.replaceWithVoid()
.onFailure().recoverWithUni(t -> logFailure(t));
}
private static Uni<Boolean> revokeAccessToken(SecurityIdentity securityIdentity) {
OidcProviderClient oidcProvider = securityIdentity.getAttribute(OidcProviderClient.class.getName());
String accessToken = securityIdentity.getCredential(AccessTokenCredential.class).getToken();
return oidcProvider.revokeAccessToken(accessToken);
}
private static Uni<Boolean> revokeRefreshToken(SecurityIdentity securityIdentity) {
OidcProviderClient oidcProvider = securityIdentity.getAttribute(OidcProviderClient.class.getName());
String refreshToken = securityIdentity.getCredential(RefreshToken.class).getToken();
return oidcProvider.revokeRefreshToken(refreshToken);
}
private static Uni<Void> logFailure(Throwable t) {
// Log failure as required
return Uni.createFrom().voidItem();
}
}