Core functionality for Keycloak OIDC/OAuth2 client adapters enabling Java applications to integrate with Keycloak identity and access management services
—
Authentication flow handling with support for bearer tokens, basic authentication, and OAuth flows. This module provides comprehensive authentication mechanisms and security context management with token refresh capabilities.
Base abstract class for request authentication providing common authentication flow logic.
/**
* Base abstract class for request authentication
*/
public abstract class RequestAuthenticator {
/**
* Constructor for request authenticator with SSL redirect port
* @param facade HTTP facade for request/response handling
* @param deployment Keycloak deployment configuration
* @param tokenStore Token storage implementation
* @param sslRedirectPort Port for SSL redirects
*/
public RequestAuthenticator(
HttpFacade facade,
KeycloakDeployment deployment,
AdapterTokenStore tokenStore,
int sslRedirectPort
);
/**
* Constructor for request authenticator without SSL redirect
* @param facade HTTP facade for request/response handling
* @param deployment Keycloak deployment configuration
*/
public RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment);
/**
* Get authentication challenge for unauthenticated requests
* @return AuthChallenge instance or null if no challenge needed
*/
public AuthChallenge getChallenge();
/**
* Perform authentication for the current request
* @return AuthOutcome indicating authentication result
*/
public AuthOutcome authenticate();
// Protected methods for subclass implementation
protected abstract OAuthRequestAuthenticator createOAuthAuthenticator();
protected BearerTokenRequestAuthenticator createBearerTokenAuthenticator();
protected BasicAuthRequestAuthenticator createBasicAuthAuthenticator();
protected QueryParameterTokenRequestAuthenticator createQueryParameterTokenRequestAuthenticator();
protected abstract void completeOAuthAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method);
protected abstract String changeHttpSessionId(boolean create);
}Authenticator for bearer token validation in API requests.
/**
* Authenticator for bearer token validation in API requests
*/
public class BearerTokenRequestAuthenticator {
/**
* Constructor for bearer token authenticator
* @param deployment Keycloak deployment configuration
*/
public BearerTokenRequestAuthenticator(KeycloakDeployment deployment);
/**
* Get authentication challenge for bearer token requests
* @return AuthChallenge for WWW-Authenticate header
*/
public AuthChallenge getChallenge();
/**
* Get the raw token string from the request
* @return Bearer token string or null if not present
*/
public String getTokenString();
/**
* Get the parsed and validated access token
* @return AccessToken instance or null if validation failed
*/
public AccessToken getToken();
/**
* Get the surrogate authentication user
* @return Surrogate user identifier or null
*/
public String getSurrogate();
/**
* Authenticate the bearer token request
* @param exchange HTTP exchange containing the request
* @return AuthOutcome indicating authentication result
*/
public AuthOutcome authenticate(HttpFacade exchange);
}Usage Examples:
// Bearer token authentication
BearerTokenRequestAuthenticator bearerAuth = new BearerTokenRequestAuthenticator(deployment);
AuthOutcome outcome = bearerAuth.authenticate(httpFacade);
if (outcome == AuthOutcome.AUTHENTICATED) {
AccessToken token = bearerAuth.getToken();
String tokenString = bearerAuth.getTokenString();
// Extract user information
String username = token.getPreferredUsername();
Set<String> roles = token.getRealmAccess().getRoles();
// Use token for authorization decisions
if (roles.contains("admin")) {
// Allow admin operations
}
} else if (outcome == AuthOutcome.FAILED) {
AuthChallenge challenge = bearerAuth.getChallenge();
// Send challenge response
}Authenticator for HTTP Basic Authentication with Keycloak credentials.
/**
* Authenticator for HTTP Basic Authentication with Keycloak credentials
*/
public class BasicAuthRequestAuthenticator {
/**
* Constructor for basic auth authenticator
* @param deployment Keycloak deployment configuration
*/
public BasicAuthRequestAuthenticator(KeycloakDeployment deployment);
/**
* Authenticate using HTTP Basic Authentication
* @param exchange HTTP exchange containing credentials
* @return AuthOutcome indicating authentication result
*/
public AuthOutcome authenticate(HttpFacade exchange);
}Usage Examples:
// Basic authentication
BasicAuthRequestAuthenticator basicAuth = new BasicAuthRequestAuthenticator(deployment);
AuthOutcome outcome = basicAuth.authenticate(httpFacade);
if (outcome == AuthOutcome.AUTHENTICATED) {
// User authenticated via basic auth
// Continue with request processing
} else {
// Send 401 Unauthorized with WWW-Authenticate header
httpFacade.getResponse().setStatus(401);
httpFacade.getResponse().setHeader("WWW-Authenticate", "Basic realm=\"keycloak\"");
}Security context providing access to tokens with automatic refresh capabilities.
/**
* Security context providing access to tokens with automatic refresh capabilities
*/
public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext {
/**
* Default constructor
*/
public RefreshableKeycloakSecurityContext();
/**
* Constructor with complete token set
* @param deployment Keycloak deployment configuration
* @param tokenStore Token storage implementation
* @param tokenString Raw access token string
* @param token Parsed access token
* @param idTokenString Raw ID token string
* @param idToken Parsed ID token
* @param refreshToken Refresh token string
*/
public RefreshableKeycloakSecurityContext(
KeycloakDeployment deployment,
AdapterTokenStore tokenStore,
String tokenString,
AccessToken token,
String idTokenString,
IDToken idToken,
String refreshToken
);
/**
* Get the current access token
* @return AccessToken instance
*/
public AccessToken getToken();
/**
* Get the raw access token string
* @return Access token as string
*/
public String getTokenString();
/**
* Get the current ID token
* @return IDToken instance
*/
public IDToken getIdToken();
/**
* Get the raw ID token string
* @return ID token as string
*/
public String getIdTokenString();
/**
* Get the refresh token
* @return Refresh token string
*/
public String getRefreshToken();
/**
* Logout the current session
* @param deployment Keycloak deployment configuration
*/
public void logout(KeycloakDeployment deployment);
/**
* Check if the security context is active
* @return true if tokens are valid and not expired
*/
public boolean isActive();
/**
* Check if token has sufficient time to live
* @param token Token to check
* @return true if token has sufficient TTL
*/
public boolean isTokenTimeToLiveSufficient(AccessToken token);
/**
* Get the deployment configuration
* @return KeycloakDeployment instance
*/
public KeycloakDeployment getDeployment();
/**
* Set current request information for token refresh
* @param deployment Keycloak deployment configuration
* @param tokenStore Token storage implementation
*/
public void setCurrentRequestInfo(KeycloakDeployment deployment, AdapterTokenStore tokenStore);
/**
* Refresh expired tokens
* @param checkActive Whether to check if context is active first
* @return true if refresh was successful
*/
public boolean refreshExpiredToken(boolean checkActive);
/**
* Set authorization context for policy enforcement
* @param authorizationContext Authorization context instance
*/
public void setAuthorizationContext(AuthorizationContext authorizationContext);
}Usage Examples:
// Create security context from tokens
RefreshableKeycloakSecurityContext securityContext = new RefreshableKeycloakSecurityContext(
deployment, tokenStore, tokenString, accessToken, idTokenString, idToken, refreshToken
);
// Check if context is active
if (securityContext.isActive()) {
AccessToken token = securityContext.getToken();
// Check if token needs refresh
if (!securityContext.isTokenTimeToLiveSufficient(token)) {
// Attempt to refresh token
boolean refreshed = securityContext.refreshExpiredToken(true);
if (refreshed) {
// Use refreshed token
token = securityContext.getToken();
}
}
// Access user information
String username = token.getPreferredUsername();
String email = token.getEmail();
Map<String, Object> customClaims = token.getOtherClaims();
}
// Logout when done
securityContext.logout(deployment);Authenticator for extracting bearer tokens from URL query parameters instead of Authorization header.
/**
* Authenticator for extracting bearer tokens from URL query parameters
*/
public class QueryParameterTokenRequestAuthenticator {
/**
* Constructor for query parameter token authenticator
* @param deployment Keycloak deployment configuration
*/
public QueryParameterTokenRequestAuthenticator(KeycloakDeployment deployment);
/**
* Get authentication challenge for query parameter token requests
* @return AuthChallenge for error responses
*/
public AuthChallenge getChallenge();
/**
* Get the raw token string from query parameters
* @return Bearer token string or null if not present
*/
public String getTokenString();
/**
* Get the parsed and validated access token
* @return AccessToken instance or null if validation failed
*/
public AccessToken getToken();
/**
* Authenticate the request using query parameter token
* @param exchange HTTP exchange containing the request
* @return AuthOutcome indicating authentication result
*/
public AuthOutcome authenticate(HttpFacade exchange);
}Usage Examples:
// Query parameter token authentication (e.g., for WebSocket connections)
QueryParameterTokenRequestAuthenticator queryAuth =
new QueryParameterTokenRequestAuthenticator(deployment);
AuthOutcome outcome = queryAuth.authenticate(httpFacade);
if (outcome == AuthOutcome.AUTHENTICATED) {
AccessToken token = queryAuth.getToken();
String tokenString = queryAuth.getTokenString();
// Token was successfully extracted from query parameter
// e.g., /api/websocket?access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
String username = token.getPreferredUsername();
} else if (outcome == AuthOutcome.FAILED) {
AuthChallenge challenge = queryAuth.getChallenge();
// Handle authentication failure
}Handler for pre-authenticated actions like CORS preflight and bearer token queries.
/**
* Handler for pre-authenticated actions like CORS preflight and bearer token queries
*/
public class AuthenticatedActionsHandler {
/**
* Constructor for authenticated actions handler
* @param deployment Keycloak deployment configuration
* @param facade OIDC HTTP facade
*/
public AuthenticatedActionsHandler(KeycloakDeployment deployment, OIDCHttpFacade facade);
/**
* Handle the request if it matches a pre-authenticated action
* @return true if request was handled, false otherwise
*/
public boolean handledRequest();
}Usage Examples:
// Handle pre-authenticated actions
AuthenticatedActionsHandler actionsHandler =
new AuthenticatedActionsHandler(deployment, oidcFacade);
if (actionsHandler.handledRequest()) {
// Request was handled (e.g., CORS preflight)
// No further processing needed
return;
}
// Continue with normal authentication flow
RequestAuthenticator authenticator = createAuthenticator(facade, deployment);
AuthOutcome outcome = authenticator.authenticate();Interface representing an authenticated OIDC account.
/**
* Interface representing an authenticated OIDC account
*/
public interface OidcKeycloakAccount extends KeycloakAccount {
/**
* Get the security context for this account
* @return KeycloakSecurityContext instance
*/
KeycloakSecurityContext getKeycloakSecurityContext();
}HTTP facade interface for OIDC operations.
/**
* HTTP facade interface for OIDC operations extending base HttpFacade
*/
public interface OIDCHttpFacade extends HttpFacade {
/**
* Get the security context for the current request
* @return KeycloakSecurityContext or null if not authenticated
*/
KeycloakSecurityContext getSecurityContext();
}Error representation for OIDC authentication failures.
/**
* Error representation for OIDC authentication failures
*/
public class OIDCAuthenticationError {
/**
* Enumeration of possible authentication error reasons
*/
public enum Reason {
NO_BEARER_TOKEN,
NO_REDIRECT_URI,
INVALID_STATE_COOKIE,
OAUTH_ERROR,
SSL_REQUIRED,
CODE_TO_TOKEN_FAILURE,
INVALID_TOKEN,
STALE_TOKEN,
NO_AUTHORIZATION_HEADER,
NO_QUERY_PARAMETER_ACCESS_TOKEN
}
/**
* Constructor for authentication error
* @param reason Error reason from enum
* @param description Detailed error description
*/
public OIDCAuthenticationError(Reason reason, String description);
/**
* Get the error reason
* @return Reason enum value
*/
public Reason getReason();
/**
* Get the error description
* @return Detailed error message
*/
public String getDescription();
/**
* String representation of the error
* @return Formatted error string
*/
public String toString();
}Usage Examples:
// Handle authentication errors
try {
AuthOutcome outcome = authenticator.authenticate();
if (outcome == AuthOutcome.FAILED) {
// Create error for client
OIDCAuthenticationError error = new OIDCAuthenticationError(
OIDCAuthenticationError.Reason.INVALID_TOKEN,
"Token signature validation failed"
);
// Log error details
logger.warn("Authentication failed: {} - {}",
error.getReason(), error.getDescription());
// Return appropriate HTTP response
sendErrorResponse(error);
}
} catch (Exception e) {
OIDCAuthenticationError error = new OIDCAuthenticationError(
OIDCAuthenticationError.Reason.CODE_TO_TOKEN_FAILURE,
"Failed to exchange authorization code for tokens: " + e.getMessage()
);
handleAuthenticationError(error);
}Install with Tessl CLI
npx tessl i tessl/maven-org-keycloak--keycloak-adapter-core