From 12c03b41ac6dd5158b36c16f4fd619f0d88ac80e Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 5 Nov 2025 09:36:09 -0600 Subject: [PATCH 1/5] feat(clerk-js): Add _clerk_skip_cache query param to token requests --- packages/clerk-js/src/core/constants.ts | 5 +++-- packages/clerk-js/src/core/resources/Session.ts | 2 +- packages/clerk-js/src/core/resources/Token.ts | 10 +++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/clerk-js/src/core/constants.ts b/packages/clerk-js/src/core/constants.ts index 98cd6bdcce9..59c9de88919 100644 --- a/packages/clerk-js/src/core/constants.ts +++ b/packages/clerk-js/src/core/constants.ts @@ -12,9 +12,10 @@ export const PRESERVED_QUERYSTRING_PARAMS = [ ]; export const CLERK_MODAL_STATE = '__clerk_modal_state'; -export const CLERK_SYNCED = '__clerk_synced'; -export const CLERK_SUFFIXED_COOKIES = 'suffixed_cookies'; export const CLERK_SATELLITE_URL = '__clerk_satellite_url'; +export const CLERK_SKIP_CACHE = '_clerk_skip_cache'; +export const CLERK_SUFFIXED_COOKIES = 'suffixed_cookies'; +export const CLERK_SYNCED = '__clerk_synced'; export const ERROR_CODES = { FORM_IDENTIFIER_NOT_FOUND: 'form_identifier_not_found', FORM_PASSWORD_INCORRECT: 'form_password_incorrect', diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index b774b12730f..7ac829ca520 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -405,7 +405,7 @@ export class Session extends BaseResource implements SessionResource { // TODO: update template endpoint to accept organizationId const params: Record = template ? {} : { organizationId }; - const tokenResolver = Token.create(path, params); + const tokenResolver = Token.create(path, params, skipCache); // Cache the promise immediately to prevent concurrent calls from triggering duplicate requests SessionTokenCache.set({ tokenId, tokenResolver }); diff --git a/packages/clerk-js/src/core/resources/Token.ts b/packages/clerk-js/src/core/resources/Token.ts index 56f3581b51c..02dfa34fbc7 100644 --- a/packages/clerk-js/src/core/resources/Token.ts +++ b/packages/clerk-js/src/core/resources/Token.ts @@ -1,6 +1,7 @@ import type { JWT, TokenJSON, TokenJSONSnapshot, TokenResource } from '@clerk/shared/types'; import { decode } from '../../utils'; +import { CLERK_SKIP_CACHE } from '../constants'; import { BaseResource } from './internal'; export class Token extends BaseResource implements TokenResource { @@ -8,11 +9,14 @@ export class Token extends BaseResource implements TokenResource { jwt?: JWT; - static async create(path: string, body: any = {}): Promise { + static async create(path: string, body: any = {}, skipCache = false): Promise { + const search = skipCache ? { [CLERK_SKIP_CACHE]: 'true' } : undefined; + const json = (await BaseResource._fetch({ - path, - method: 'POST', body, + method: 'POST', + path, + search, })) as unknown as TokenJSON; return new Token(json, path); From 7037be57bb5cfc7509b7db8177485c4a5fcc59fe Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 5 Nov 2025 09:52:52 -0600 Subject: [PATCH 2/5] update query string param construction and add test --- packages/clerk-js/src/core/resources/Token.ts | 9 +-- .../core/resources/__tests__/Token.test.ts | 55 ++++++++++++++++++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/packages/clerk-js/src/core/resources/Token.ts b/packages/clerk-js/src/core/resources/Token.ts index 02dfa34fbc7..5dd0227e797 100644 --- a/packages/clerk-js/src/core/resources/Token.ts +++ b/packages/clerk-js/src/core/resources/Token.ts @@ -1,8 +1,9 @@ import type { JWT, TokenJSON, TokenJSONSnapshot, TokenResource } from '@clerk/shared/types'; -import { decode } from '../../utils'; -import { CLERK_SKIP_CACHE } from '../constants'; -import { BaseResource } from './internal'; +import { CLERK_SKIP_CACHE } from '@/core/constants'; +import { decode } from '@/utils'; + +import { BaseResource } from './Base'; export class Token extends BaseResource implements TokenResource { pathRoot = 'tokens'; @@ -10,7 +11,7 @@ export class Token extends BaseResource implements TokenResource { jwt?: JWT; static async create(path: string, body: any = {}, skipCache = false): Promise { - const search = skipCache ? { [CLERK_SKIP_CACHE]: 'true' } : undefined; + const search = skipCache ? `${CLERK_SKIP_CACHE}=true` : undefined; const json = (await BaseResource._fetch({ body, diff --git a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts index aed2f6f2863..cd3acd30c60 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts @@ -1,10 +1,10 @@ import type { InstanceType } from '@clerk/shared/types'; import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; -import { mockFetch, mockNetworkFailedFetch } from '@/test/core-fixtures'; +import { mockFetch, mockJwt, mockNetworkFailedFetch } from '@/test/core-fixtures'; import { debugLogger } from '@/utils/debug'; -import { SUPPORTED_FAPI_VERSION } from '../../constants'; +import { CLERK_SKIP_CACHE, SUPPORTED_FAPI_VERSION } from '../../constants'; import { createFapiClient } from '../../fapiClient'; import { BaseResource } from '../internal'; import { Token } from '../Token'; @@ -44,7 +44,7 @@ describe('Token', () => { }); describe('with offline browser and network failure', () => { - let warnSpy; + let warnSpy: ReturnType; beforeEach(() => { Object.defineProperty(window.navigator, 'onLine', { @@ -103,5 +103,54 @@ describe('Token', () => { }); }); }); + + it('creates token successfully with valid response', async () => { + mockFetch(true, 200, { jwt: mockJwt }); + BaseResource.clerk = { getFapiClient: () => createFapiClient(baseFapiClientOptions) } as any; + + const token = await Token.create('/path/to/tokens', { organizationId: 'org_123' }); + + expect(global.fetch).toHaveBeenCalledTimes(1); + const [url, options] = (global.fetch as Mock).mock.calls[0]; + expect(url.toString()).toContain('https://clerk.example.com/v1/path/to/tokens'); + expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + expect(options).toMatchObject({ + body: 'organization_id=org_123', + credentials: 'include', + method: 'POST', + }); + expect(token).toBeInstanceOf(Token); + expect(token.jwt).toBeDefined(); + }); + + it('creates token with skipCache=false by default', async () => { + mockFetch(true, 200, { jwt: mockJwt }); + BaseResource.clerk = { getFapiClient: () => createFapiClient(baseFapiClientOptions) } as any; + + await Token.create('/path/to/tokens'); + + const [url] = (global.fetch as Mock).mock.calls[0]; + expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + }); + + it('creates token with skipCache=true and includes query parameter', async () => { + mockFetch(true, 200, { jwt: mockJwt }); + BaseResource.clerk = { getFapiClient: () => createFapiClient(baseFapiClientOptions) } as any; + + await Token.create('/path/to/tokens', {}, true); + + const [url] = (global.fetch as Mock).mock.calls[0]; + expect(url.toString()).toContain(`${CLERK_SKIP_CACHE}=true`); + }); + + it('creates token with skipCache=false explicitly and excludes query parameter', async () => { + mockFetch(true, 200, { jwt: mockJwt }); + BaseResource.clerk = { getFapiClient: () => createFapiClient(baseFapiClientOptions) } as any; + + await Token.create('/path/to/tokens', {}, false); + + const [url] = (global.fetch as Mock).mock.calls[0]; + expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + }); }); }); From d8830bd7e13fd0031c34a693cdbe2734cb45ce09 Mon Sep 17 00:00:00 2001 From: Jacek Date: Wed, 5 Nov 2025 10:39:49 -0600 Subject: [PATCH 3/5] changeset --- .changeset/old-wombats-tease.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/old-wombats-tease.md diff --git a/.changeset/old-wombats-tease.md b/.changeset/old-wombats-tease.md new file mode 100644 index 00000000000..7e6a9a77d4f --- /dev/null +++ b/.changeset/old-wombats-tease.md @@ -0,0 +1,5 @@ +--- +'@clerk/clerk-js': patch +--- + +Added \_clerk_skip_cache query string param to token requests initiated with skipCache option From f7b8955df03dbf30900602f33dab8a0007af6b8e Mon Sep 17 00:00:00 2001 From: Jacek Date: Thu, 20 Nov 2025 21:33:34 -0600 Subject: [PATCH 4/5] rename param --- packages/clerk-js/src/core/constants.ts | 1 - packages/clerk-js/src/core/resources/Token.ts | 3 +-- .../src/core/resources/__tests__/Token.test.ts | 10 +++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/clerk-js/src/core/constants.ts b/packages/clerk-js/src/core/constants.ts index f85c9e49f9a..bddf6b20541 100644 --- a/packages/clerk-js/src/core/constants.ts +++ b/packages/clerk-js/src/core/constants.ts @@ -13,7 +13,6 @@ export const PRESERVED_QUERYSTRING_PARAMS = [ export const CLERK_MODAL_STATE = '__clerk_modal_state'; export const CLERK_SATELLITE_URL = '__clerk_satellite_url'; -export const CLERK_SKIP_CACHE = '_clerk_skip_cache'; export const CLERK_SUFFIXED_COOKIES = 'suffixed_cookies'; export const CLERK_SYNCED = '__clerk_synced'; export const ERROR_CODES = { diff --git a/packages/clerk-js/src/core/resources/Token.ts b/packages/clerk-js/src/core/resources/Token.ts index 5dd0227e797..2b75d8b3c52 100644 --- a/packages/clerk-js/src/core/resources/Token.ts +++ b/packages/clerk-js/src/core/resources/Token.ts @@ -1,6 +1,5 @@ import type { JWT, TokenJSON, TokenJSONSnapshot, TokenResource } from '@clerk/shared/types'; -import { CLERK_SKIP_CACHE } from '@/core/constants'; import { decode } from '@/utils'; import { BaseResource } from './Base'; @@ -11,7 +10,7 @@ export class Token extends BaseResource implements TokenResource { jwt?: JWT; static async create(path: string, body: any = {}, skipCache = false): Promise { - const search = skipCache ? `${CLERK_SKIP_CACHE}=true` : undefined; + const search = skipCache ? `debug=skip_cache` : undefined; const json = (await BaseResource._fetch({ body, diff --git a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts index cd3acd30c60..bd1830cb4e5 100644 --- a/packages/clerk-js/src/core/resources/__tests__/Token.test.ts +++ b/packages/clerk-js/src/core/resources/__tests__/Token.test.ts @@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from 'vite import { mockFetch, mockJwt, mockNetworkFailedFetch } from '@/test/core-fixtures'; import { debugLogger } from '@/utils/debug'; -import { CLERK_SKIP_CACHE, SUPPORTED_FAPI_VERSION } from '../../constants'; +import { SUPPORTED_FAPI_VERSION } from '../../constants'; import { createFapiClient } from '../../fapiClient'; import { BaseResource } from '../internal'; import { Token } from '../Token'; @@ -113,7 +113,7 @@ describe('Token', () => { expect(global.fetch).toHaveBeenCalledTimes(1); const [url, options] = (global.fetch as Mock).mock.calls[0]; expect(url.toString()).toContain('https://clerk.example.com/v1/path/to/tokens'); - expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + expect(url.toString()).not.toContain('debug=skip_cache'); expect(options).toMatchObject({ body: 'organization_id=org_123', credentials: 'include', @@ -130,7 +130,7 @@ describe('Token', () => { await Token.create('/path/to/tokens'); const [url] = (global.fetch as Mock).mock.calls[0]; - expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + expect(url.toString()).not.toContain('debug=skip_cache'); }); it('creates token with skipCache=true and includes query parameter', async () => { @@ -140,7 +140,7 @@ describe('Token', () => { await Token.create('/path/to/tokens', {}, true); const [url] = (global.fetch as Mock).mock.calls[0]; - expect(url.toString()).toContain(`${CLERK_SKIP_CACHE}=true`); + expect(url.toString()).toContain('debug=skip_cache'); }); it('creates token with skipCache=false explicitly and excludes query parameter', async () => { @@ -150,7 +150,7 @@ describe('Token', () => { await Token.create('/path/to/tokens', {}, false); const [url] = (global.fetch as Mock).mock.calls[0]; - expect(url.toString()).not.toContain(CLERK_SKIP_CACHE); + expect(url.toString()).not.toContain('debug=skip_cache'); }); }); }); From e4c878b90e1383fd187c1fb75c9dd9716f6ddbe3 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Thu, 20 Nov 2025 22:11:15 -0600 Subject: [PATCH 5/5] Apply suggestion from @brkalow --- .changeset/old-wombats-tease.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/old-wombats-tease.md b/.changeset/old-wombats-tease.md index 7e6a9a77d4f..7c099c005e5 100644 --- a/.changeset/old-wombats-tease.md +++ b/.changeset/old-wombats-tease.md @@ -2,4 +2,4 @@ '@clerk/clerk-js': patch --- -Added \_clerk_skip_cache query string param to token requests initiated with skipCache option +Added debug query param to token requests initiated with `skipCache` option.