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.
> >> >>
> >> >>
> >>
> >>
>

Reply via email to