Skip to content

fix: remove duplicate trailing slash from client_assertion audience#236

Open
samjetski wants to merge 1 commit into
auth0:mainfrom
samjetski:feat/fix-audience
Open

fix: remove duplicate trailing slash from client_assertion audience#236
samjetski wants to merge 1 commit into
auth0:mainfrom
samjetski:feat/fix-audience

Conversation

@samjetski

Copy link
Copy Markdown

Description

The OnAuthorizationCodeReceived handler builds the aud claim for the Private Key JWT client assertion sent to /oauth/token. Since v1.7.0 it has been double-appending the trailing slash:

var audience = Utils.ToAuthority(issuer) + "/";

Utils.ToAuthority (added in #206) already normalises its input to a value ending in /, so the resulting audience becomes https://{tenant}// (two slashes). Auth0's /oauth/token endpoint validates that aud exactly matches the tenant token endpoint with a single trailing slash, so it rejects the assertion with 401 invalid_client.

The visible symptom for affected apps (any app configured with ClientAssertionSecurityKey) is a callback loop: the OIDC middleware can't complete the code-for-token exchange, retries /authorize, Auth0's SSO cookie immediately returns a new code, and the cycle repeats. Server logs show:

Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler
Message contains error: 'invalid_client', error_description: 'Unauthorized',
error_uri: 'error_uri is null', status code '401'.

The companion TokenClient path (used for refresh-token exchange in TokenClient.cs:68) already used the single-slash form $"https://{domain}/" and was unaffected — so the fix brings the OIDC callback path back in line with it.

The change is a one-line removal of the duplicate + "/".

References

Testing

The existing integration test Should_Send_ClientAssertion_To_Token_Endpoint only asserted that a client_assertion form parameter was present, which is how this slipped through. It has been strengthened to:

  1. Capture the assertion JWT from the token-endpoint request body via a new HttpRequestMessage.GetClientAssertion() test helper.
  2. Decode it and assert Audiences contains exactly https://{domain}/ (single trailing slash), plus that Issuer and Subject equal the configured ClientId.

Verified by temporarily reverting the fix — the new assertion fails with the buggy double-slash audience; restoring the fix passes.

Full integration suite: 205/205 passing locally on net10.0.

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation for new/changed functionality in this PR or in auth0.com/docs
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not main

@samjetski samjetski marked this pull request as ready for review May 28, 2026 07:06
@samjetski samjetski requested a review from a team as a code owner May 28, 2026 07:06
@kailash-b

Copy link
Copy Markdown
Contributor

Hi @samjetski 👋

Thanks a lot of flagging this. Appreciate you taking the effort to help fix it as well.

We will take a look at this PR, in the meanwhile, can you please sign the commit?
Our pipelines, mandate the commit to be signed in-order to merge.

We will also make sure that this ask (mandatory signed commit) is clear in our contributing guidelines and PR template checklist.

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.

2 participants