Re: Cannot invoke "org.eclipse.microprofile.auth.LoginConfig.authMethod()" because "loginConfig" is null

Richard Zowalla <[email protected]> Sat, 12 Jul 2025 14:02:21 +0200
Newsgroups gmane.comp.java.openejb.user
Message-ID <DF867FC3-9B3D-4089-8474-41863DB6DC4B__9321.49581364996$1752321800$gmane$org@apache.org>
Hi,

I think this is were things are going to be complicated ;-)=20

Hard to say what the reason could possibly be in your EAR setup.

=46rom 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=C3=9F
Richard


> Am 12.07.2025 um 11:08 schrieb Java Entwicklung =
<[email protected]>:
>=20
> Hello Richard,
>=20
> 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)..
>=20
> 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.
>=20
> ------ here's what I used to ask ChatGPT about the issue but it wasn't =
much
> of a help ----
>=20
> 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
>=20
> The backend app itself has its own java/tomcat security layer, =
consisting
> of realms, policies, roles, users, etc.
>=20
> 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.
>=20
> 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).
>=20
> 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.
>=20
> 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.
> ---------------------------------------------------------------------
>=20
> I hope this sheds some light on my setup and you will know what the =
issue
> is.
>=20
>=20
> On Fri, 11 Jul 2025 at 20:03, Richard Zowalla <[email protected]> wrote:
>=20
>> Hi,
>>=20
>> Had a quick look at your example:
>> https://github.com/javac9/tomee-with-jwt-demo
>>=20
>> You shouldn=E2=80=99t bundle the API=E2=80=99s in your web app. In =
TomEE, these libs are
>> shipped with the container, i.e
>> should be in compileOnly scope:
>>=20
>>    implementation("org.apache.tomee:jakartaee-api:10.0")
>>=20
>>=20
>> =
implementation("org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1=
=E2=80=9C)
>>=20
>> If you change that and do a full WAR rebuild, the web app will =
deploy:
>>=20
>> 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
>>=20
>> Since I don=E2=80=99t have a key cloak setup available, it will =
subsequently fail
>> ;-)
>>=20
>> Gru=C3=9F
>> Richard
>>=20
>>=20
>>> Am 11.07.2025 um 14:54 schrieb Java Entwicklung =
<[email protected]>:
>>>=20
>>> ```
>>> # Tested with:
>>> tomee docker image: tomee:plus
>>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.1
>>>=20
>>> # but same is with:
>>> tomee docker image: tomee:10.1-jre21-plus
>>> org.eclipse.microprofile.jwt:microprofile-jwt-auth-api:2.2-RC1
>>> ```
>>>=20
>>> Hello,
>>>=20
>>> I created a demo Jakarta EE 10 app and configured it so it =
authenticates
>>> incoming requests to my protected resource against my Keycloak =
instance.
>>>=20
>>> 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=3D/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=3D[/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
>>>=20
>> =
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
>>>=20
>> =
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
>>>=20
>> =
org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecuto=
rService.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
>>>=20
>> =
org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:303)=

>>> 2025-07-11T11:55:43.628255587Z at
>>>=20
>> =
org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.ja=
va:109)
>>> 2025-07-11T11:55:43.628256899Z at
>>>=20
>> =
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
>>>=20
>> =
org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:77=
6)
>>> 2025-07-11T11:55:43.628261506Z at
>>>=20
>> =
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
>>>=20
>> =
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:=
1203)
>>> 2025-07-11T11:55:43.628275693Z at
>>>=20
>> =
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
>>>=20
>> =
org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecuto=
rService.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
>>>=20
>> =
org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:74=
9)
>>> 2025-07-11T11:55:43.628284925Z at
>>>=20
>> =
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
>>>=20
>> =
org.apache.catalina.core.StandardService.startInternal(StandardService.jav=
a:412)
>>> 2025-07-11T11:55:43.628289236Z at
>>> org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:164)
>>> 2025-07-11T11:55:43.628290566Z at
>>>=20
>> =
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
>>>=20
>> =
[StandardEngine[Catalina].StandardHost[localhost].StandardContext[/demoapp=
]]
>>> 2025-07-11T11:55:43.628307498Z at
>>>=20
>> =
org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBa=
se.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
>>>=20
>> =
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
>>>=20
>> =
org.apache.tomee.microprofile.jwt.MPJWTInitializer.onStartup(MPJWTInitiali=
zer.java:45)
>>> 2025-07-11T11:55:43.628316658Z at
>>>=20
>> =
org.apache.catalina.core.StandardContext.startInternal(StandardContext.jav=
a: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:
>>>=20
>>> ```
>>> @ApplicationScoped
>>> @ApplicationPath("/api")
>>> @LoginConfig(authMethod=3D"MP-JWT")
>>> @DeclareRoles({
>>>       "admin-role",
>>>       "user-role"
>>> })
>>> public class HelloApplication extends Application {
>>>=20
>>> }
>>>=20
>>> // is a separate class
>>> @Path("/v1")
>>> @Produces("text/plain")
>>> public class HelloResource {
>>>=20
>>>   @GET
>>>   @Path("/admin")
>>>   @RolesAllowed("admin-role")
>>>   public String helloAdmin() {
>>>       return "Hello, Admin!";
>>>   }
>>>=20
>>>   @GET
>>>   @Path("/user")
>>>   public String hello() {
>>>       return "Hello, user!";
>>>   }
>>>=20
>>> }
>>> ```
>>>=20
>>> In `src/main/resources/META-INF/microprofile-config.properties` I =
have:
>>> ```
>>> # JWT Configuration
>>> mp.jwt.verify.issuer=3Dhttp://auth.localhost:8090/realms/myrealm
>>> mp.jwt.verify.publickey.location=3D
>>> =
http://auth.localhost:8090/realms/myrealm/protocol/openid-connect/certs
>>> ```
>>> and my `src/main/webapp/WEB-INF/web.xml` contains:
>>> ```
>>> <?xml version=3D"1.0" encoding=3D"UTF-8"?>
>>> <web-app xmlns=3D"https://jakarta.ee/xml/ns/jakartaee"
>>>        xmlns:xsi=3D"http://www.w3.org/2001/XMLSchema-instance"
>>>        xsi:schemaLocation=3D"https://jakarta.ee/xml/ns/jakartaee
>>> https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
>>>        version=3D"6.0">
>>>=20
>>>=20
>>> </web-app>
>>> ```
>>>=20
>>> 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).
>>>=20
>>>=20
>>> Note that removing `@LoginConfig(authMethod=3D"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`.
>>>=20
>>> Also note that I have tested with various other TomEE flavours of =
version
>>> 10 - but no difference.
>>=20
>>=20