The reason is technically accurate — the code did fall through to a static-token comparison and it did mismatch — but it is actively misleading. static_token_mismatch reads as "the caller presented the wrong token". The truth was "the server's JWT validator is dead, so a correct token had no chance of validating". The fields even contradict each other: token_type: "jwt" next to a static token failure is the tell, and it is easy to miss.
This misdirection propagated all the way to the user: claude.ai surfaced Authorization with gitea failed. You can check your credentials and permissions. The credentials were valid. Time went into re-running the Authentik OAuth flow before the server logs were read.
Proposed fix
When a JWT is presented and the validator is unavailable, log a distinct reason:
Reserve static_token_mismatch for token_type: "static". Never let a JWT path report a static-token failure.
Consider also returning 503 rather than 401 in this case: the server is degraded, the request is not unauthorized. A 503 would tell an upstream client to retry rather than tell a user to check their credentials.
Acceptance criterion
A test asserting that with a nil/failed validator, a well-formed JWT yields reason jwt_validator_unavailable (not static_token_mismatch).
Refs
Companion to the one-shot validator init issue.
Observed on v0.11.0, koala k3s, 2026-07-17.
## Problem
When the JWT validator failed to initialize, every rejected JWT logged this:
```
WARN mcp auth rejected reason="static_token_mismatch" status=401 token_type="jwt" token_fp="872d2da957ac" path="/mcp"
```
The reason is technically accurate — the code did fall through to a static-token comparison and it did mismatch — but it is actively misleading. `static_token_mismatch` reads as "the caller presented the wrong token". The truth was "the server's JWT validator is dead, so a correct token had no chance of validating". The fields even contradict each other: `token_type: "jwt"` next to a *static* token failure is the tell, and it is easy to miss.
This misdirection propagated all the way to the user: claude.ai surfaced `Authorization with gitea failed. You can check your credentials and permissions.` The credentials were valid. Time went into re-running the Authentik OAuth flow before the server logs were read.
## Proposed fix
When a JWT is presented and the validator is unavailable, log a distinct reason:
```
WARN mcp auth rejected reason="jwt_validator_unavailable" status=401 token_type="jwt" ...
```
Reserve `static_token_mismatch` for `token_type: "static"`. Never let a JWT path report a static-token failure.
Consider also returning 503 rather than 401 in this case: the server is degraded, the request is not unauthorized. A 503 would tell an upstream client to retry rather than tell a user to check their credentials.
## Acceptance criterion
A test asserting that with a nil/failed validator, a well-formed JWT yields reason `jwt_validator_unavailable` (not `static_token_mismatch`).
## Refs
- Companion to the one-shot validator init issue.
- Observed on v0.11.0, koala k3s, 2026-07-17.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
When the JWT validator failed to initialize, every rejected JWT logged this:
The reason is technically accurate — the code did fall through to a static-token comparison and it did mismatch — but it is actively misleading.
static_token_mismatchreads as "the caller presented the wrong token". The truth was "the server's JWT validator is dead, so a correct token had no chance of validating". The fields even contradict each other:token_type: "jwt"next to a static token failure is the tell, and it is easy to miss.This misdirection propagated all the way to the user: claude.ai surfaced
Authorization with gitea failed. You can check your credentials and permissions.The credentials were valid. Time went into re-running the Authentik OAuth flow before the server logs were read.Proposed fix
When a JWT is presented and the validator is unavailable, log a distinct reason:
Reserve
static_token_mismatchfortoken_type: "static". Never let a JWT path report a static-token failure.Consider also returning 503 rather than 401 in this case: the server is degraded, the request is not unauthorized. A 503 would tell an upstream client to retry rather than tell a user to check their credentials.
Acceptance criterion
A test asserting that with a nil/failed validator, a well-formed JWT yields reason
jwt_validator_unavailable(notstatic_token_mismatch).Refs