JWT Headers authentication cache reused across different JWTs sharing the same subject

Hi,

I would like to report a possible bug, or perhaps an opportunity for improvement, in the JWT Headers community module related to authentication cache reuse.

Environment

  • GeoServer: 3.0.0
  • JWT Headers plugin: 3.0.0
  • Authentication header: Authorization: Bearer <token>
  • Username extracted from JWT claim: sub
  • Roles extracted from JWT claim: aut

Based on code inspection, the same behavior may also affect other GeoServer / JWT Headers versions that still use the inherited cache key logic in GeoServerPreAuthenticatedUserNameFilter / GeoServerPreAuthenticationFilter.

Problem

When two different JWTs share the same sub, GeoServer appears to reuse the same cached Authentication, even if the roles in the second token are different.

Example:

Token A:
{
“sub”: “user-123”,
“aut”: [“ROLE_A”]
}

Token B:
{
“sub”: “user-123”,
“aut”:
}

Observed behavior:

  1. request with token A is authenticated successfully.
  2. second request with token B, using the same sub, still appears to reuse the roles from token A.

Expected behavior:

  • token B should be processed independently
  • the resulting roles should reflect token B, not token A

Why I think this happens

From debugging and code inspection, it looks like GeoServerJwtHeadersFilter inherits the default pre-authentication cache key behavior.
That means the cache key is effectively based on the principal returned by the filter.
With this configuration, the principal is extracted from sub, so two different tokens with the same sub may share the same cache entry.

Additional observation

If I configure the username claim to use jti instead of sub, the problem disappears.
That suggests the cache key is based on the logical user identity rather than the token identity.

Proposed direction

A possible fix would be to override getCacheKey(HttpServletRequest) in GeoServerJwtHeadersFilter so that:

  • the authenticated principal still comes from the configured username claim
  • the cache key depends on the token instance, for example:
    • JWT hash
    • or jti
    • or disabling cache usage for this filter when roles are derived from the token

Thanks.