ThemeSelectorProviderFactory not used by keycloak 7

Hi there,

It’s now a couple of days I’m trying to use a ThemeSelectorProviderFactory on keycloak 7.0.0
I implemented it like this :

@JBossLog
public class MyThemeSelectorProviderFactory implements ThemeSelectorProviderFactory {


    @Override
    public ThemeSelectorProvider create(KeycloakSession keycloakSession) {
        log.debug("create theme selector");


        if(keycloakSession != null && keycloakSession.getContext() != null && keycloakSession.getContext().getRealm()!= null && keycloakSession.getContext().getRealm().getName() !=null && "sandbox".equalsIgnoreCase(keycloakSession.getContext().getRealm().getName())){
            log.debug("create :"+keycloakSession.getContext().getRealm().getName());

            log.debug("realm :"+keycloakSession.getContext().getRealm().getName());
            return new MyThemeSelectorProvider(keycloakSession);
        }

        return new DefaultThemeSelectorProvider(keycloakSession);
    }

    @Override
    public void init(Config.Scope scope) {

        log.debug("Theme selector factory init");
    }

    @Override
    public void postInit(KeycloakSessionFactory keycloakSessionFactory) {

        keycloakSessionFactory.create().
        log.debug("Theme selector factory postInit");
    }

    @Override
    public void close() {
        log.debug("Theme selector factory close");
    }

    @Override
    public String getId() {
        return "MyThemeSelector";
    }




@JBossLog
public class MyThemeSelectorProvider implements ThemeSelectorProvider {

    private final KeycloakSession session;

    public MyThemeSelectorProvider(KeycloakSession session) {
       this.session = session;
    }

    @Override
    public String getThemeName(Theme.Type type) {

        String name = null;
        log.debug("type :"+type.name());
        switch (type) {
            case WELCOME:
                name = Config.scope("theme").get("welcomeTheme");
                break;
            case LOGIN:
                ClientModel client = session.getContext().getClient();
                String clientName = client.getName();
                log.debug("client :"+type.name());
                if (client != null) {
                    if("client-mobile".equalsIgnoreCase(clientName)){
                        name = "myCustomTheme";
                    }
                }

                if (name == null || name.isEmpty()) {
                    name = session.getContext().getRealm().getLoginTheme();
                }

                break;
            case ACCOUNT:
                name = session.getContext().getRealm().getAccountTheme();
                break;
            case EMAIL:
                name = session.getContext().getRealm().getEmailTheme();
                break;
            case ADMIN:
                name = session.getContext().getRealm().getAdminTheme();
                break;
        }

        if (name == null || name.isEmpty()) {
            name = Config.scope("theme").get("default", Version.NAME.toLowerCase());
        }

        return name;

    }

    @Override
    public void close() {
    }
}

I can see it initializing :

Nov 27 09:09:14 keycloak.srv1 sh[105375]: [Server:server-two] 09:09:14,874 DEBUG [com.xxx.keycloak.theme.MyThemeSelectorProviderFactory] (MSC service thread 1-2) Theme selector factory init 14h06
Nov 27 09:09:14 keycloak.srv1 sh[105375]: [Server:server-one] 09:09:14,928 DEBUG [com.xxx.keycloak.theme.MyThemeSelectorProviderFactory] (MSC service thread 1-1) Theme selector factory postInit
Nov 27 09:09:15 keycloak.srv1 sh[105375]: [Server:server-one] 09:09:15,110 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 50) WFLYSRV0010: Deployed "my-theme-selector-bundle-1.0.0-SNAPSHOT.ear" (runtime-name : "my-theme-selector-bundle-1.0.0-SNAPSHOT.ear")

The issue is that it never get called, I can’t see no logs of log.debug(“create theme selector”); and it keeps using the default theme selector everywhere

Any help/advice is more than welcome

have a good day

1 Like

any findings on this one?

have the exact same problem. The provider is deployed, but the create method is never called when the login page is loaded, so there is no way to make it select a different theme.

For whoever needs something like this in the future, including my future self.

In order to make your custom theme selector SPI actually work (might apply to other types of SPIs, interestingly not for UserStorageProviders though, those work just fine as per the documentation), you need to declare it as the default one so it takes over DefaultThemeSelectorProvider.

Otherwise, although your custom provider is initialized, the create method in the Provider Factory class is never called.

In order to declare your Theme Selector as the default one, instead of declaring it like this (as documented here):

<spi name="themeSelector">
       <provider name="my-theme-selector-provider" enabled="true"/>
</spi>

You should declare it like this:

<spi name="themeSelector">
       <default-provider>my-theme-selector-provider</default-provider>
       <provider name="my-theme-selector-provider" enabled="true"/>
</spi>

and voilá.

The main cause of this problem is perhaps that Keycloak doesn’t seem to have a section in the admin interface to specify that your custom SPI should be used instead of the default one (or at least I haven’t found any).

Worth mentioning that I did all this on Keycloak 11, not in version 7.

4 Likes

thanks for sharing this

1 Like