From 527170fb898f4be15f82f29c93df0ac3a392bc3f Mon Sep 17 00:00:00 2001 From: Dominic Couture Date: Tue, 16 Jun 2026 14:43:46 +0100 Subject: [PATCH] fix(backend): Enforce azp when configured Enforce the `azp` (authorized party) claim when `authorizedParties` is configured. Previously, a session token that was missing the `azp` claim was accepted even when `authorizedParties` was set, allowing the authorized-parties check to be bypassed by omitting the claim. Now, when `authorizedParties` is configured, a token with a missing or empty `azp` claim is rejected. Tokens without `azp` continue to be accepted when no `authorizedParties` are configured. --- .changeset/warm-spies-double.md | 5 +++++ .../backend/src/jwt/__tests__/assertions.test.ts | 13 ++++++++++++- packages/backend/src/jwt/assertions.ts | 10 ++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 .changeset/warm-spies-double.md diff --git a/.changeset/warm-spies-double.md b/.changeset/warm-spies-double.md new file mode 100644 index 00000000000..4d588c6960b --- /dev/null +++ b/.changeset/warm-spies-double.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': patch +--- + +Enforce the `azp` (authorized party) claim when `authorizedParties` is configured. Previously, a session token that was missing the `azp` claim was accepted even when `authorizedParties` was set, allowing the authorized-parties check to be bypassed by omitting the claim. Now, when `authorizedParties` is configured, a token with a missing or empty `azp` claim is rejected. Tokens without `azp` continue to be accepted when no `authorizedParties` are configured. diff --git a/packages/backend/src/jwt/__tests__/assertions.test.ts b/packages/backend/src/jwt/__tests__/assertions.test.ts index 63ac0169296..c61f09bf9e2 100644 --- a/packages/backend/src/jwt/__tests__/assertions.test.ts +++ b/packages/backend/src/jwt/__tests__/assertions.test.ts @@ -204,10 +204,21 @@ describe('assertSubClaim(sub?)', () => { }); describe('assertAuthorizedPartiesClaim(azp?, authorizedParties?)', () => { - it('does not throw if azp missing or empty', () => { + it('does not throw if azp missing or empty and no authorizedParties are configured', () => { expect(() => assertAuthorizedPartiesClaim()).not.toThrow(); expect(() => assertAuthorizedPartiesClaim('')).not.toThrow(); expect(() => assertAuthorizedPartiesClaim(undefined)).not.toThrow(); + expect(() => assertAuthorizedPartiesClaim('', [])).not.toThrow(); + expect(() => assertAuthorizedPartiesClaim(undefined, [])).not.toThrow(); + }); + + it('throws error if azp is missing or empty but authorizedParties are configured', () => { + expect(() => assertAuthorizedPartiesClaim('', ['azp-1'])).toThrow( + `Invalid JWT Authorized party claim (azp) "". Expected "azp-1".`, + ); + expect(() => assertAuthorizedPartiesClaim(undefined, ['azp-1'])).toThrow( + `Invalid JWT Authorized party claim (azp) undefined. Expected "azp-1".`, + ); }); it('does not throw if authorizedParties missing or empty', () => { diff --git a/packages/backend/src/jwt/assertions.ts b/packages/backend/src/jwt/assertions.ts index 074d3f14c30..8ab74096f7e 100644 --- a/packages/backend/src/jwt/assertions.ts +++ b/packages/backend/src/jwt/assertions.ts @@ -84,11 +84,17 @@ export const assertSubClaim = (sub?: string) => { }; export const assertAuthorizedPartiesClaim = (azp?: string, authorizedParties?: string[]) => { - if (!azp || !authorizedParties || authorizedParties.length === 0) { + // When no authorized parties are configured there is nothing to enforce, so + // an azp-less token is accepted (a warning is surfaced elsewhere). + if (!authorizedParties || authorizedParties.length === 0) { return; } - if (!authorizedParties.includes(azp)) { + // Once authorized parties are configured the azp claim must be present and + // match one of them. Returning early on a missing/empty azp would let any + // token bypass the authorized-parties check simply by omitting the claim, + // defeating the purpose of configuring them. + if (!azp || !authorizedParties.includes(azp)) { throw new TokenVerificationError({ reason: TokenVerificationErrorReason.TokenInvalidAuthorizedParties, message: `Invalid JWT Authorized party claim (azp) ${JSON.stringify(azp)}. Expected "${authorizedParties}".`,