Skip to content

Don't attach a stale client-assertion error description to unrelated token errors - #896

Merged
JoeShook merged 1 commit into
developfrom
fix/stale-client-assertion-error-description
Oct 5, 2026
Merged

JoeShook merged 1 commit into
developfrom
fix/stale-client-assertion-error-description

Conversation

@JoeShook

@JoeShook JoeShook commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Problem

When a client assertion fails UDAP validation, UdapJwtSecretValidator records an error description in HttpContext.Items. UdapTokenResponseMiddleware then injects that description into any 400 token response that has none of its own.

Duende runs secret validators as a composite, so another ISecretValidator can still authenticate the client afterwards (for example, private_key_jwt against a registered JWKS, with no x5c). The stale description then leaks into unrelated errors. A revoked refresh token, for instance, comes back as:

{ "error": "invalid_grant", "error_description": "Client assertion JWT validation failed" }

That points the client at its authentication, which was fine, rather than at the grant.

Fix

  • UdapJwtSecretValidator: an assertion with no x5c header is not a UDAP client assertion. The validator now declines it quietly, without recording a description, and leaves the decision to the next validator.
  • UdapTokenResponseMiddleware: the stored description is injected only when the error is invalid_client. Injection of authorization-extension extensions is unchanged.

Tests

New tests in AuthorizationExtensionEnforcementTests:

  • Another secret validator authenticates the client, then a bad refresh token is presented. The response is a plain invalid_grant with no description. Without the fix, this test fails with "Client assertion JWT validation failed".
  • An authorization-extension validator returns invalid_grant with error extensions. The response still carries its error_description and extensions.

The existing TokenRequest_TamperedJwt_Returns_InvalidClient_With_ErrorDescription test still shows that a real UDAP assertion failure returns invalid_client with the description.

UdapServer.Tests: 369 passed, 3 skipped.

🤖 Generated with Claude Code

…token errors

UdapJwtSecretValidator records an error description in HttpContext.Items
when a client assertion fails UDAP validation, and UdapTokenResponseMiddleware
injects it into any 400 token response that lacks one. When another
ISecretValidator then authenticates the client (e.g. private_key_jwt against
a registered JWKS), that text was attached to unrelated errors, so a revoked
refresh token came back as invalid_grant "Client assertion JWT validation
failed".

- UdapJwtSecretValidator declines an assertion with no x5c header without
  recording a description, since it is not a UDAP client assertion.
- UdapTokenResponseMiddleware injects the stored description only on
  invalid_client. Error extensions are still injected as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JoeShook
JoeShook merged commit 4da9a81 into develop Oct 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant