FTL templates in theme-resources/templates/ not loading in Keycloak-x

Hi All,

I think I found a bug in Keycloak-x ftl template loading. Posting here to see if anyone is seeing the same behavior. This is a description of an extension that works fine in Keycloak.

  1. Place an .ftl template in the src/main/resorces/theme-resources/templates/ dir of any extension
  2. Create an Authenticator or custom REST endpoint that serves the template, like:
  ...
  return session.getProvider(LoginFormsProvider.class).createForm("foo.ftl");
}
...
  1. Deploy the extension to the providers/ dir of Keycloak-x (standard distribution or docker)
  2. Get the following error, where the template cannot be found:
2022-02-07 20:06:27,898 ERROR [org.key.for.log.fre.FreeMarkerLoginFormsProvider] (executor-thread-0) Failed to process template: org.keycloak.theme.FreeMarkerException: Failed to process template foo.ftl
	at org.keycloak.theme.FreeMarkerUtil.processTemplate(FreeMarkerUtil.java:71)
	at org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider.processTemplate(FreeMarkerLoginFormsProvider.java:512)
	at org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider.createForm(FreeMarkerLoginFormsProvider.java:302)
	at com.example.FooResourceProvider.foo(FooResourceProvider.java:63)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
	at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
	at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
	at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
	at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
	at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
	at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
	at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
	at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
	at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
	at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
	at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:135)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:81)
	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:41)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:362)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:340)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
	at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:66)
	at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: freemarker.template.TemplateNotFoundException: Template not found for name "foo.ftl".
The name was interpreted by this TemplateLoader: org.keycloak.theme.FreeMarkerUtil$ThemeTemplateLoader@1e633f79.
	at freemarker.template.Configuration.getTemplate(Configuration.java:2883)
	at freemarker.template.Configuration.getTemplate(Configuration.java:2703)
	at org.keycloak.theme.FreeMarkerUtil.getTemplate(FreeMarkerUtil.java:85)
	at org.keycloak.theme.FreeMarkerUtil.processTemplate(FreeMarkerUtil.java:64)
	... 52 more

Does anyone have similar problems?

Thanks!

This is indeed broken in the new 17.0.0 Quarkus distribution of Keycloak. In order to use theme-resources in extensions, you must use a workaround like this:

Thanks @thomasdarimont !

Hm… :thinking:
Can‘t repdroduce the error…

I‘m using a custom authenticator with custom .ftl file with my dasniko/keycloak-2fa-sms-authenticator. When I deploy this to recent KC17, it works ootb. The template is found and displayed.

What do I do wrong for not getting the error?

BTW: Your linked file is no more available, Thomas just removed it…!

Hm. Maybe a bugfix made it into 17. I’ll check to see why it wasn’t working with the pre-release but it’s working now.

1 Like

I’m seeing this back again in 19.0.1.

@dasniko I tried your sms authenticator and got the following result:

keycloak_1  | 2022-08-17 04:47:49,350 ERROR [org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider] (executor-thread-14) Failed to process template: org.keycloak.theme.FreeMarkerException: Failed to process template update-mobile-number.ftl
keycloak_1  | 	at org.keycloak.theme.FreeMarkerUtil.processTemplate(FreeMarkerUtil.java:71)
keycloak_1  | 	at org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider.processTemplate(FreeMarkerLoginFormsProvider.java:524)
keycloak_1  | 	at org.keycloak.forms.login.freemarker.FreeMarkerLoginFormsProvider.createForm(FreeMarkerLoginFormsProvider.java:326)
keycloak_1  | 	at dasniko.keycloak.requiredaction.MobileNumberRequiredAction.createForm(MobileNumberRequiredAction.java:77)
keycloak_1  | 	at dasniko.keycloak.requiredaction.MobileNumberRequiredAction.requiredActionChallenge(MobileNumberRequiredAction.java:39)
keycloak_1  | 	at org.keycloak.services.managers.AuthenticationManager.executeAction(AuthenticationManager.java:1310)
keycloak_1  | 	at org.keycloak.services.managers.AuthenticationManager.lambda$executionActions$18(AuthenticationManager.java:1258)
keycloak_1  | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
keycloak_1  | 	at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:400)
keycloak_1  | 	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
keycloak_1  | 	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
keycloak_1  | 	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
keycloak_1  | 	at java.base/java.util.stream.DistinctOps$1$2.end(DistinctOps.java:168)
keycloak_1  | 	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
keycloak_1  | 	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:503)
keycloak_1  | 	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:488)
keycloak_1  | 	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
keycloak_1  | 	at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
keycloak_1  | 	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
keycloak_1  | 	at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:543)
keycloak_1  | 	at org.keycloak.services.managers.AuthenticationManager.executionActions(AuthenticationManager.java:1259)
keycloak_1  | 	at org.keycloak.services.managers.AuthenticationManager.actionRequired(AuthenticationManager.java:1147)
keycloak_1  | 	at org.keycloak.services.managers.AuthenticationManager.nextActionAfterAuthentication(AuthenticationManager.java:994)
keycloak_1  | 	at org.keycloak.services.resources.LoginActionsService.processRequireAction(LoginActionsService.java:996)
keycloak_1  | 	at org.keycloak.services.resources.LoginActionsService.requiredActionGET(LoginActionsService.java:978)
keycloak_1  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
keycloak_1  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
keycloak_1  | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
keycloak_1  | 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
keycloak_1  | 	at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
keycloak_1  | 	at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
keycloak_1  | 	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
keycloak_1  | 	at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
keycloak_1  | 	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90)
keycloak_1  | 	at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
keycloak_1  | 	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
keycloak_1  | 	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
keycloak_1  | 	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545)
keycloak_1  | 	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
keycloak_1  | 	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
keycloak_1  | 	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
keycloak_1  | 	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
keycloak_1  | 	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
keycloak_1  | 	at java.base/java.lang.Thread.run(Thread.java:829)
keycloak_1  | Caused by: freemarker.template.TemplateNotFoundException: Template not found for name "update-mobile-number.ftl".
keycloak_1  | The name was interpreted by this TemplateLoader: org.keycloak.theme.FreeMarkerUtil$ThemeTemplateLoader@418d109c.
keycloak_1  | 	at freemarker.template.Configuration.getTemplate(Configuration.java:2883)
keycloak_1  | 	at freemarker.template.Configuration.getTemplate(Configuration.java:2703)
keycloak_1  | 	at org.keycloak.theme.FreeMarkerUtil.getTemplate(FreeMarkerUtil.java:85)
keycloak_1  | 	at org.keycloak.theme.FreeMarkerUtil.processTemplate(FreeMarkerUtil.java:58)
keycloak_1  | 	... 73 more
keycloak_1  |
keycloak_1  | 2022-08-17 04:47:49,354 ERROR [org.keycloak.headers.DefaultSecurityHeadersProvider] (executor-thread-14) MediaType not set on path /auth/realms/self/login-actions/required-action, with response status 500
keycloak_1  | 2022-08-17 04:47:49,367 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-14) Uncaught server error: javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
keycloak_1  | 	at org.keycloak.headers.DefaultSecurityHeadersProvider.addHeaders(DefaultSecurityHeadersProvider.java:75)
keycloak_1  | 	at org.keycloak.services.filters.KeycloakSecurityHeadersFilter.filter(KeycloakSecurityHeadersFilter.java:40)
keycloak_1  | 	at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:361)
keycloak_1  | 	at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:252)
keycloak_1  | 	at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:101)
keycloak_1  | 	at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:74)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:594)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:524)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
keycloak_1  | 	at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
keycloak_1  | 	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
keycloak_1  | 	at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
keycloak_1  | 	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
keycloak_1  | 	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak_1  | 	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
keycloak_1  | 	at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90)
keycloak_1  | 	at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
keycloak_1  | 	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
keycloak_1  | 	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
keycloak_1  | 	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545)
keycloak_1  | 	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
keycloak_1  | 	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
keycloak_1  | 	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
keycloak_1  | 	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
keycloak_1  | 	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
keycloak_1  | 	at java.base/java.lang.Thread.run(Thread.java:829)
keycloak_1  |
1 Like

Bug filed:

Thanks @xgp for coming up with this.
I didn’t have time yet to test all my extensions, I only noticed that the sms authenticator doesn’t work, without investigating why. But it seems that you are right, no changes in code and it doesn’t work with 19+

With this behavior and the fact that the new admin ui is more than buggy, I can’t recommend upgrading to KC19 atm. Dissappointing.

1 Like

Seems there is already a fix available, so we have to wait for the next release (hopefully soon a patch release). :slightly_smiling_face:

Workaround:
If you use a custom theme, put the resources/template files into your custom theme, then they will be found.

1 Like

@dasniko Thanks. I ran the nightly and the fix works.

Thanks for the workaround. I already had done that for my own use. I was more concerned about people that were using extensions I have shipped.

Hi All,

I’ve got the same error using any of 17, 18 or 19 KC version. Freemarker just cannot find templates in resources/theme-resources directory.
CustomClasspathThemeResourceProviderFactory does not work for me.
Maybe I do smth wrong?

I’m using embedded keyclok from here and @dasniko 's 2FA Example .

Yes, most probably.

But what? We don’t know, you don’t tell us anything.
Also, this embedded KC stuff is very experimental (and I don’t have any clue about this).

@dasniko tell pls, what would you recommend to use for KC customization?
Download sources, put custom provider to special folders and then build?

Download sources

No, don‘t (never) deal with the sources! Take the compiled binaries or the Docker image!

put custom provider to special folders and then build

Yes, create your providers, compile them to a .jar file, put this into the /opt/keycloak/providers folder (when using Docker, in case of deployment into filesystem, look for the providers folder under the KC root folder), then start/build the Keycloak image (see docs what „build“ is meant here).

Oh got it. Thanks @dasniko !

Could you tell me another thing: how could I use your 2FA with oauth2 authorization? I mean case when client do request for getting jwt token and then pass it to rest api’s to get access?