Thanks for all this detail. I don't recall the default in MP JWT off the top
of my head. Would need to consult the spec, possibly TCK if the spec didn't
have a clear answer. Note if the spec isn't clear, let me know and I'll update
it once we find the answer.
I can confirm that calling and caching getPrincipal before an HTTP request is
read is not valid for any HTTP-based security mechanism; basic auth, digest
auth, jwt, http session based, soap security, etc, etc. It rules out
everything except SSL/TLS certificate-based client authentication, which is
connection based.
Even if they waited till the HTTP message was read and cached for the duration
of just the request, that's still not really possible because of these methods:
- HttpServletRequest.login(String username, String password);
- HttpServletRequest.logout();
- HttpServletRequest.authenticate(HttpServletResponse response);
What they actually do, if anything at all, is completely dependent on the
underlying security framework. As is the concept of how long a security
identity lasts during a request.
Sounds like a situation where someone is using security framework X which is
slow, so some well-intentioned code got added that ultimately isn't valid
outside of that exact user's scenario.
Here's how I would approach resolving this:
- Find the commit that added the caching
- The commit message might tell on itself (x system is slow so let's cache)
- Figure out how they imagined the caching would work: when things are
removed, added, and in what scope they imagined the cached value was valid
(request, session, connection, globally).
- Analyze a stack trace of the first getPrincipal that's cached. Figure out
how we possibly got there as it's not valid. Even if caching is removed, you
still can't call getPrincipal without an HTTP request, so this has to be solved
and fixed.
-David
> On Feb 17, 2026, at 6:18 AM, Richard Zowalla <[email protected]> wrote:
>
> I believe the actual issue is related to the caching mechanism in CXF's
> updated code. Due to this caching, the token validation now happens as soon
> as getPrincipal() is called, which occurs much earlier in CXF 4.2.0 than in
> previous versions.
>
> As a result, our current TomEE code fails because at that point in the
> request lifecycle, no Authorization header may be present (e.g., for
> @PermitAll endpoints), and the token validation simply fails.
>
> Additionally, I couldn't find clear guidance in the MP JWT specification
> regarding the default behavior for non-annotated JAX-RS methods, i.e.,
> methods without @RolesAllowed, @PermitAll, or @DenyAll.
>
> It appears this may be vendor-specific. Should the default be:
> • @PermitAll (allow unauthenticated access)?
> • @DenyAll (require authentication)?
> • Something else?
>
> Gruß
> Richard
>
>
>
>> Am 17.02.2026 um 14:54 schrieb Richard Zowalla <[email protected]>:
>>
>> Hi all,
>>
>> Due to a change in CXF 4.2.0 [1], specifically caching the principal instead
>> of looking it up on demand, we are seeing several test failures in the MP
>> JWT area - I am now wondering if this a thing CXF needs to address or if we
>> need to update our integration. For this reason and after some debugging, I
>> would like to get some additional context from the past regarding the
>> architecture of our CXF/MP JWT integration :)
>>
>> The failure in question can be reproduced by running
>> OrderTest#shouldBeRunning() from the main branch in
>> examples/mp-rest-jwt-principal, or by executing parts of the MP JWT TCK,
>> which are also failing.
>>
>> The test calls an endpoint that, according to the test assumptions,
>> shouldn’t be protected. It passes on TomEE 10 / CXF 4.1.5 (which does not
>> cache the principal). The relevant code on our side is mainly in
>> MPJWTFilter, especially the MPJWTServletRequestWrapper and its use of
>> validate(…).
>>
>> Since I’m not an active MP JWT user, I have some (maybe dumb?) questions:
>>
>> According to [2], an application annotated with @LoginConfig(authMethod =
>> "MP-JWT") requires MP-JWT Access Control (potentially for all endpoints?).
>>
>> If that is the case, the status() method of OrderRestin
>> https://github.com/apache/tomee/blob/main/examples/mp-rest-jwt-principal/src/main/java/org/superbiz/store/rest/OrderRest.java
>> should require a JWT, no?
>>
>> However, we don’t add a token to the REST client in
>> https://github.com/apache/tomee/blob/main/examples/mp-rest-jwt-principal/src/test/java/org/superbiz/store/OrderRestClient.java#L35,
>> so the request is sent without a bearer token and fails with a 401.
>>
>> This worked on TomEE 10 / CXF 4.1.5 and earlier.
>>
>> I suspect some MP JWT TCK failures are caused by the same issue. See the
>> build here:
>> https://ci-builds.apache.org/job/TomEe/job/master-build-full/org.apache.tomee$microprofile-jwt-tck/2071/
>>
>> Question:
>>
>> What is the expected behavior? From my reading of the spec, it seems this
>> endpoint shouldn’t be invocable without a valid token?
>>
>> Could anyone with more experience in this area (David, JL, anyone?) provide
>> some insight?
>>
>> Thanks and Gruß
>> Richard
>>
>> [1]
>> https://github.com/apache/cxf/pull/2807/changes#diff-eddf423fac99200bd14e115467dc35809e1855cefdf3bae77f9394b8c050fc94L419
>> [2]
>> https://download.eclipse.org/microprofile/microprofile-jwt-auth-2.1/microprofile-jwt-auth-spec-2.1.html#_marking_a_jax_rs_application_as_requiring_mp_jwt_access_control
>>
>