Description
Before reporting an issue
- I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.
Area
token-exchange
Describe the bug
I am migrating from Keycloak 15 to 26 and faced follwong problem when trying to implement custom token exchange provider for external token exchange purposes.
Earlier there was class DefaultTokenExchangeProvider I extended from and everything was fine and clear. In release 26.2.x there are new AbstractTokenExchangeProvider class and 2 childs: StandardTokenExchangeProvider (for internal-internal) and V1TokenExchangeProvider (for others purposes), moreover last one is not recomended to use as it's in preview mode.
Version
26.2.5
Regression
- The issue is a regression
Expected behavior
Custom TokenExchangeProvider is to work instead of Standard/V1
Actual behavior
Standard/V1 TokenExchangeProvider keeps working in spite of implementing CustomTokenProviderFactory``
How to Reproduce?
My factory class:
public class MyTokenExchangeProviderFactory implements TokenExchangeProviderFactory, EnvironmentDependentProviderFactory {
private static final String PROVIDER_ID = "standard" (or "default");
@Override
public TokenExchangeProvider create(KeycloakSession keycloakSession) {
return new MyTokenExchangeProvider();
}
@Override
public void init(Config.Scope scope) {}
@Override
public void postInit(KeycloakSessionFactory keycloakSessionFactory) {}
@Override
public void close() {}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
public int order() {
return 20; // 10 - for Standard and specifying more than 10 must have set priority to my provider but it seems not work
}
@Override
public boolean isSupported(Config.Scope scope) {
return Profile.isFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE_STANDARD_V2);
}
or
@Override
public boolean isSupported(Config.Scope scope) {
return Profile.isFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE);
}
depending on what class I'm extending from.
META-INF/services: org.keycloak.protocol.oidc.TokenExchangeProviderFactory
org.example.factory.MyTokenExchangeProviderFactory
MyTokenExchangeProvider class:
public class MyTokenExchangeProvider extends StandardTokenExchangeProvider (or V1TokenExchangeProvider) {
@Override
public boolean supports(TokenExchangeContext tokenExchangeContext) {
return false;
}
@Override
public Response exchange(TokenExchangeContext context) {
this.params = context.getParams();
this.formParams = context.getFormParams();
this.session = context.getSession();
this.cors = context.getCors();
this.realm = context.getRealm();
this.client = context.getClient();
this.event = context.getEvent();
this.clientConnection = context.getClientConnection();
this.headers = context.getHeaders();
this.tokenManager = (TokenManager) context.getTokenManager();
this.clientAuthAttributes = context.getClientAuthAttributes();
this.context = context;
this.audience = context.getFormParams().getFirst("audience");
if (client.getClientId().equals(KEYCLOAK_EXCHANGE_CLIENT_ID)) {
return tokenExchange(); // Class for custom logic I'd like to implement
}
return super.exchange(context);
}
@Override
public Response tokenExchange() {
//My custom logic here }
Anything else?
No response