Hello, Actually it turns out, it is CDI vs (Open)EJB issue.
If my resource is annotated with: @RequestScoped (or no such annotation) then it works fine. But at the moment I have to keep my: @Stateless @LocalBean annotations in order not to have to manually manage transactions. Any ideas? On Sat, 12 Jul 2025 at 22:00, Richard Zowalla <[email protected]> wrote: > Most likely around > https://github.com/apache/tomee/blob/main/mp-jwt/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java > as a start. > > Am 12. Juli 2025 21:41:33 MESZ schrieb Java Entwicklung < > [email protected]>: > >Thanks! Where (which libs and methods) would you set your breakpoints if > >you were to debug why access to the protected method was denied? > > > >On Sat, 12 Jul 2025 at 14:03, Richard Zowalla <[email protected]> wrote: > > > >> Hi, > >> > >> I think this is were things are going to be complicated ;-) > >> > >> Hard to say what the reason could possibly be in your EAR setup. > >> > >> From what I remember is, that EARs make things always a bit more > >> complicated due to the special classloader hierarchies involved. > >> > >> I would double check, that no (api) libs provide by the container are > >> available in the WAR archives, EJB modules or in the shared libs of the > EAR. > >> Next step would be to remote debug the application for a specific > request > >> to see, what actually goes wrong on the container / configuration side > of > >> things. > >> > >> Gruß > >> Richard > >> > >> > >> > Am 12.07.2025 um 11:08 schrieb Java Entwicklung < > [email protected]>: > >> > > >> > Hello Richard, > >> > > >> > Yes indeed, that was the problem! It starts just fine on the demo app > and > >> > with my keycloak details it authenticates and authorizes as expected. > >> > However, in the real app where I need this, it is giving me 403 > (meaning > >> > authentication worked but "admin-role" is somehow still > unrecognised).. > >> > > >> > So far I developed and used my custom app without Keycloak. I could > >> > delegate the requests to the app-core without issues (because my proxy > >> war > >> > app was already there - within the EAR of that backend system. > >> > But now, when I'm touching the roles, it seems not to recognise my > >> Keycloak > >> > roles ("admin-role", "user-role") and gives me 403. > >> > > >> > ------ here's what I used to ask ChatGPT about the issue but it wasn't > >> much > >> > of a help ---- > >> > > >> > My backend app is deployed to TomEE 10 as an EAR. That ear consists of > >> > several WARs, most important ones being: > >> > * app-core.war --> the core of the backend > >> > * app-rest.war --> the rest layer > >> > * my-custom-proxy-app.war --> I added this as proxy layer; external > >> backend > >> > clients (like mobile apps, web apps, desktop apps, etc. send their > >> requests > >> > to this app and it then delegates to the core backend > >> > > >> > The backend app itself has its own java/tomcat security layer, > consisting > >> > of realms, policies, roles, users, etc. > >> > > >> > Now, I want my client apps AND my proxy app (my-custom-proxy-app.war) > to > >> > use keycloak for authentication and authorization. On the client apps' > >> end > >> > it is working and the requests are being sent with a valid bearer > token. > >> > > >> > In TomEE I'm using MP-JWT and it is able to confirm validity of the > token > >> > so a request to a protected resource doesn't return 401 (sign that it > >> > authenticated successfully) - but rather it is returning 403, meaning > >> that > >> > the role ("admin-role") that is contained in my Keycloak's token is > not > >> > recognized (the role is correctly included under "groups" - it's done > on > >> > Keycloak level and is the same keycloak instance I used with the demo > >> app, > >> > where it worked). > >> > > >> > Important: > >> > * I don't need my "admin-role" available across other WARs - just in > this > >> > my-custom-proxy-app.war > >> > * role in token is correctly configured - I built a demo app where a > >> single > >> > WAR is deployed to TomEE and I get 200 for a protected resource > >> > * everything else, including annotations and MP config is set exactly > how > >> > it is set up in the demo app > >> > * I can see backend's roles being defined in > >> > <EAR>/META-INF/application.xml, and then once again in > >> > <EAR>/app-core/WEB-INF/web.xml -- I tried adding "admin-role" role > >> > definition to both of those places but it changed nothing. > >> > > >> > That means, somehow the whole backend application expects my > "admin-role" > >> > from the token to be part of backend app's security realm. The thing > is: > >> i > >> > don't know how everything works in such a set up. > >> > --------------------------------------------------------------------- > >> > > >> > I hope this sheds some light on my setup and you will know what the > issue > >> > is. > >> > > >> > > >> > On Fri, 11 Jul 2025 at 20:03, Richard Zowalla <[email protected]> > wrote: > >> > > >> >> Hi, > >> >> > >> >> Had a quick look at your example: > >> >> https://github.com/javac9/tomee-with-jwt-demo > >> >> > >> >> You shouldn’t bundle the API’s in your web app. In TomEE, these libs > are > >> >> shipped with the container, i.e > >> >> should be in compileOnly scope: > >> >> > >> >> implementation("org.apache.tomee:jakartaee-api:10.0") > >> >> > >> >> > >> >> > >> > implementation("org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1“) > >> >> > >> >> If you change that and do a full WAR rebuild, the web app will > deploy: > >> >> > >> >> tomee | 11-Jul-2025 18:00:33.859 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints REST > >> >> Application: http://localhost:8080/demoapp/api -> > >> >> com.example.tomeewithjwtdemo.HelloApplication@5fd8302e > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> Service URI: http://localhost:8080/demoapp/api/health -> > Pojo > >> >> org.apache.tomee.microprofile.health.MicroProfileHealthChecksEndpoint > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/health -> > Response > >> >> getChecks() > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/health/live -> > Response > >> >> getLiveChecks() > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/health/ready -> > Response > >> >> getReadyChecks() > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/health/started -> > Response > >> >> getStartedChecks() > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> Service URI: http://localhost:8080/demoapp/api/v1 -> > Pojo > >> >> com.example.tomeewithjwtdemo.HelloResource > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/v1/admin -> > String > >> >> helloAdmin() > >> >> tomee | 11-Jul-2025 18:00:33.862 INFO [main] > >> >> org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logEndpoints > >> >> GET http://localhost:8080/demoapp/api/v1/user -> > String > >> >> hello() > >> >> tomee | 11-Jul-2025 18:00:33.880 INFO [main] > >> >> java.lang.reflect.Method.invoke Deployment of web application archive > >> >> [/usr/local/tomee/webapps/demoapp.war] has finished in [1,420] ms > >> >> > >> >> Since I don’t have a key cloak setup available, it will subsequently > >> fail > >> >> ;-) > >> >> > >> >> Gruß > >> >> Richard > >> >> > >> >> > >> >>> Am 11.07.2025 um 14:54 schrieb Java Entwicklung < > [email protected] > >> >: > >> >>> > >> >>> ``` > >> >>> # Tested with: > >> >>> tomee docker image: tomee:plus > >> >>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1 > >> >>> > >> >>> # but same is with: > >> >>> tomee docker image: tomee:10.1-jre21-plus > >> >>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.2-RC1 > >> >>> ``` > >> >>> > >> >>> Hello, > >> >>> > >> >>> I created a demo Jakarta EE 10 app and configured it so it > >> authenticates > >> >>> incoming requests to my protected resource against my Keycloak > >> instance. > >> >>> > >> >>> It works successfully with Payara Micro 6 but with TomEE 10.0 > (which is > >> >>> what I need and have to use) it fails on startup with the following: > >> >>> ``` > >> >>> 11-Jul-2025 11:55:42.801 WARNING [main] > >> >>> org.apache.batchee.container.services.ServicesManager.init You > didn't > >> >>> specify org.apache.batchee.jmx.application and JMX is already > >> registered, > >> >>> skipping > >> >>> 2025-07-11T11:55:42.804794711Z 11-Jul-2025 11:55:42.804 INFO [main] > >> >>> org.apache.openejb.assembler.classic.Assembler.createApplication > >> Deployed > >> >>> Application(path=/usr/local/tomee/webapps/demoapp) > >> >>> 2025-07-11T11:55:43.426149580Z 11-Jul-2025 11:55:43.425 INFO [main] > >> >>> org.apache.myfaces.webapp.MyFacesContainerInitializer.onStartup > Using > >> >>> org.apache.myfaces.webapp.MyFacesContainerInitializer > >> >>> 2025-07-11T11:55:43.614818412Z 11-Jul-2025 11:55:43.614 INFO [main] > >> >>> org.apache.myfaces.webapp.MyFacesContainerInitializer.onStartup > Added > >> >>> FacesServlet with mappings=[/faces/*, *.jsf, *.faces, *.xhtml] > >> >>> 2025-07-11T11:55:43.628173897Z 11-Jul-2025 11:55:43.626 SEVERE > [main] > >> >>> java.lang.reflect.Method.invoke Error deploying web application > archive > >> >>> [/usr/local/tomee/webapps/demoapp.war] > >> >>> 2025-07-11T11:55:43.628209564Z java.lang.IllegalStateException: > Error > >> >>> starting child > >> >>> 2025-07-11T11:55:43.628212292Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:602) > >> >>> 2025-07-11T11:55:43.628214272Z at > >> >>> > org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:571) > >> >>> 2025-07-11T11:55:43.628215708Z at > >> >>> > org.apache.catalina.core.StandardHost.addChild(StandardHost.java:654) > >> >>> 2025-07-11T11:55:43.628217070Z at > >> >>> > org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:965) > >> >>> 2025-07-11T11:55:43.628218545Z at > >> >>> > >> >> > >> > org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1903) > >> >>> 2025-07-11T11:55:43.628219991Z at > >> >>> > java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown > >> >>> Source) > >> >>> 2025-07-11T11:55:43.628221298Z at > >> >>> java.base/java.util.concurrent.FutureTask.run(Unknown Source) > >> >>> 2025-07-11T11:55:43.628222601Z at > >> >>> > >> >> > >> > org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) > >> >>> 2025-07-11T11:55:43.628224008Z at > >> >>> > java.base/java.util.concurrent.AbstractExecutorService.submit(Unknown > >> >>> Source) > >> >>> 2025-07-11T11:55:43.628236311Z at > >> >>> > org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:769) > >> >>> 2025-07-11T11:55:43.628238350Z at > >> >>> > org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:420) > >> >>> 2025-07-11T11:55:43.628239666Z at > >> >>> org.apache.catalina.startup.HostConfig.start(HostConfig.java:1621) > >> >>> 2025-07-11T11:55:43.628241335Z at > >> >>> > >> >> > >> > org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303) > >> >>> 2025-07-11T11:55:43.628255587Z at > >> >>> > >> >> > >> > org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:109) > >> >>> 2025-07-11T11:55:43.628256899Z at > >> >>> > >> >> > >> > org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:389) > >> >>> 2025-07-11T11:55:43.628258590Z at > >> >>> > org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:336) > >> >>> 2025-07-11T11:55:43.628259958Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:776) > >> >>> 2025-07-11T11:55:43.628261506Z at > >> >>> > >> >> > >> > org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:772) > >> >>> 2025-07-11T11:55:43.628263034Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) > >> >>> 2025-07-11T11:55:43.628274187Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1203) > >> >>> 2025-07-11T11:55:43.628275693Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1193) > >> >>> 2025-07-11T11:55:43.628277030Z at > >> >>> java.base/java.util.concurrent.FutureTask.run(Unknown Source) > >> >>> 2025-07-11T11:55:43.628280369Z at > >> >>> > >> >> > >> > org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) > >> >>> 2025-07-11T11:55:43.628281839Z at > >> >>> > java.base/java.util.concurrent.AbstractExecutorService.submit(Unknown > >> >>> Source) > >> >>> 2025-07-11T11:55:43.628283322Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:749) > >> >>> 2025-07-11T11:55:43.628284925Z at > >> >>> > >> >> > >> > org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:203) > >> >>> 2025-07-11T11:55:43.628286472Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) > >> >>> 2025-07-11T11:55:43.628287734Z at > >> >>> > >> >> > >> > org.apache.catalina.core.StandardService.startInternal(StandardService.java:412) > >> >>> 2025-07-11T11:55:43.628289236Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) > >> >>> 2025-07-11T11:55:43.628290566Z at > >> >>> > >> >> > >> > org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:870) > >> >>> 2025-07-11T11:55:43.628292404Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) > >> >>> 2025-07-11T11:55:43.628293861Z at > >> >>> org.apache.catalina.startup.Catalina.start(Catalina.java:761) > >> >>> 2025-07-11T11:55:43.628295318Z at > >> >>> > >> java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown > >> >>> Source) > >> >>> 2025-07-11T11:55:43.628301199Z at > >> >>> java.base/java.lang.reflect.Method.invoke(Unknown Source) > >> >>> 2025-07-11T11:55:43.628302697Z at > >> >>> org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345) > >> >>> 2025-07-11T11:55:43.628304266Z at > >> >>> org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:476) > >> >>> 2025-07-11T11:55:43.628305690Z Caused by: > >> >>> org.apache.catalina.LifecycleException: Failed to start component > >> >>> > >> >> > >> > [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/demoapp]] > >> >>> 2025-07-11T11:55:43.628307498Z at > >> >>> > >> >> > >> > org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:406) > >> >>> 2025-07-11T11:55:43.628309026Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:179) > >> >>> 2025-07-11T11:55:43.628310551Z at > >> >>> > >> >> > >> > org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:599) > >> >>> 2025-07-11T11:55:43.628312065Z ... 35 more > >> >>> 2025-07-11T11:55:43.628313380Z Caused by: > >> java.lang.NullPointerException: > >> >>> Cannot invoke > "org.eclipse.microprofile.auth.LoginConfig.authMethod()" > >> >>> because "loginConfig" is null > >> >>> 2025-07-11T11:55:43.628315144Z at > >> >>> > >> >> > >> > org.apache.tomee.microprofile.jwt.MPJWTInitializer.onStartup(MPJWTInitializer.java:45) > >> >>> 2025-07-11T11:55:43.628316658Z at > >> >>> > >> >> > >> > org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4464) > >> >>> 2025-07-11T11:55:43.628320249Z at > >> >>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164) > >> >>> 2025-07-11T11:55:43.628321622Z ... 36 more > >> >>> 2025-07-11T11:55:43.632485224Z 11-Jul-2025 11:55:43.632 INFO [main] > >> >>> java.lang.reflect.Method.invoke Deployment of web application > archive > >> >>> [/usr/local/tomee/webapps/demoapp.war] has finished in [3,177] ms > >> >>> 2025-07-11T11:55:43.637611803Z 11-Jul-2025 11:55:43.637 INFO [main] > >> >>> java.lang.reflect.Method.invoke Starting ProtocolHandler > >> >> ["http-nio-8080"] > >> >>> 2025-07-11T11:55:43.649430271Z 11-Jul-2025 11:55:43.649 INFO [main] > >> >>> java.lang.reflect.Method.invoke Server startup in [3311] > milliseconds > >> >>> ``` > >> >>> Here's how I configured it: > >> >>> > >> >>> ``` > >> >>> @ApplicationScoped > >> >>> @ApplicationPath("/api") > >> >>> @LoginConfig(authMethod="MP-JWT") > >> >>> @DeclareRoles({ > >> >>> "admin-role", > >> >>> "user-role" > >> >>> }) > >> >>> public class HelloApplication extends Application { > >> >>> > >> >>> } > >> >>> > >> >>> // is a separate class > >> >>> @Path("/v1") > >> >>> @Produces("text/plain") > >> >>> public class HelloResource { > >> >>> > >> >>> @GET > >> >>> @Path("/admin") > >> >>> @RolesAllowed("admin-role") > >> >>> public String helloAdmin() { > >> >>> return "Hello, Admin!"; > >> >>> } > >> >>> > >> >>> @GET > >> >>> @Path("/user") > >> >>> public String hello() { > >> >>> return "Hello, user!"; > >> >>> } > >> >>> > >> >>> } > >> >>> ``` > >> >>> > >> >>> In `src/main/resources/META-INF/microprofile-config.properties` I > have: > >> >>> ``` > >> >>> # JWT Configuration > >> >>> mp.jwt.verify.issuer=http://auth.localhost:8090/realms/myrealm > >> >>> mp.jwt.verify.publickey.location= > >> >>> > >> http://auth.localhost:8090/realms/myrealm/protocol/openid-connect/certs > >> >>> ``` > >> >>> and my `src/main/webapp/WEB-INF/web.xml` contains: > >> >>> ``` > >> >>> <?xml version="1.0" encoding="UTF-8"?> > >> >>> <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" > >> >>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > >> >>> xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee > >> >>> https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" > >> >>> version="6.0"> > >> >>> > >> >>> > >> >>> </web-app> > >> >>> ``` > >> >>> > >> >>> I run gradle war, mount it to my tomee container's deployment dir > and > >> >> start > >> >>> it. Again, this exact setup worked perfectly with Payara - the idea > was > >> >> to > >> >>> make sure the config is correct before trying to solve startup > issue in > >> >>> TomEE (sure, TomEE might require something differently). > >> >>> > >> >>> > >> >>> Note that removing `@LoginConfig(authMethod="MP-JWT")` annotation on > >> the > >> >>> class and using: > >> >>> ``` > >> >>> <login-config> > >> >>> <auth-method>MP-JWT</auth-method> > >> >>> </login-config> > >> >>> ``` > >> >>> doesn't have the same effect! There is no such startup error but all > >> >>> resources return `404 Not found`. > >> >>> > >> >>> Also note that I have tested with various other TomEE flavours of > >> version > >> >>> 10 - but no difference. > >> >> > >> >> > >> > >> >
