Location of theme-resources/resources

From the documentation about Theme resources:

The easiest way to load additional theme resources is to create a JAR with templates in theme-resources/templates resources in theme-resources/resources and messages bundles in theme-resources/messages and drop it into the standalone/deployments/ directory of Keycloak.

I have a js and css file in theme-resources/resources that I want to reference from my .ftl in theme-resources/templates. When I’m building a login theme, this is achieved by using ${url.resourcesPath}, but that doesn’t work in this case.

Does anyone know the path I can use to reference resource files in theme-resources/resources?

Thank you!

Posting the response of @thomasdarimont from the mailing list:

I stumbled upon this very same problem a few years ago and couldn’t find a direct way to solve this back then, and I think it’s still not explicitly supported at the moment.

However, I found another way of providing extension specific resources by shipping a custom theme with the extensions with the resources. This gives you a predictable name to refer to resources.

This old post contains an example for this: [keycloak-user] Identity First authentication flow and trick for extension specific theme resources - keycloak-user - Jboss List Archives

However I think the resource lookup should be extended to also be able to lookup resources from the themes-resources folder of an extension jar. This would make it much easier to ship self-contained extensions with UIs.

Following Thomas’s post, I also was able to use the extension-specific theme idea along with a custom resource to render the resource url without a relative ../..

  public Response foo() {
    Theme theme = getTheme("foo");
    UriInfo uriInfo = session.getContext().getUri();
    UriBuilder uriBuilder =
    URI resourcePath = uriBuilder.build();
    return session.getProvider(LoginFormsProvider.class).setAttribute("fooResources", resourcePath.toString()).createForm("foo.ftl");

  private Theme getTheme(String name) {
    try {
      return session.theme().getTheme(name, Theme.Type.LOGIN);
    } catch (IOException e) {
      throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
1 Like