From 99c56deb38b162d54172cbd2e2198e117b1ce2f6 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 13:15:51 -0700 Subject: [PATCH 01/13] chore: add get-auth typing tests --- packages/backend/package.json | 6 ++--- .../src/tokens/__tests__/types.test-d.ts | 26 +++++++++++++++++++ packages/backend/src/tokens/types.ts | 8 +++--- 3 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 packages/backend/src/tokens/__tests__/types.test-d.ts diff --git a/packages/backend/package.json b/packages/backend/package.json index 337bcce1ad4..6d9773ff53f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -98,9 +98,9 @@ "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "run-s test:node test:edge-runtime test:cloudflare-miniflare", - "test:cloudflare-miniflare": "vitest run --environment miniflare", - "test:edge-runtime": "vitest run --environment edge-runtime", - "test:node": "vitest run --environment node", + "test:cloudflare-miniflare": "vitest run --typecheck --environment miniflare", + "test:edge-runtime": "vitest run --typecheck --environment edge-runtime", + "test:node": "vitest run --typecheck --environment node", "test:watch": "run-s test:watch:node test:watch:edge-runtime test:watch:cloudflare-miniflare", "test:watch:cloudflare-miniflare": "vitest watch --environment miniflare", "test:watch:edge-runtime": "vitest watch --environment edge-runtime", diff --git a/packages/backend/src/tokens/__tests__/types.test-d.ts b/packages/backend/src/tokens/__tests__/types.test-d.ts new file mode 100644 index 00000000000..3f834c9df92 --- /dev/null +++ b/packages/backend/src/tokens/__tests__/types.test-d.ts @@ -0,0 +1,26 @@ +import { expectTypeOf, test } from 'vitest'; + +import type { GetAuthFn, MachineAuthObject, SessionAuthObject } from '../types'; + +test('infers the correct AuthObject type for each accepted token type', () => { + const request = new Request('https://example.com'); + + // Across our SDKs, we have a getAuth() function + const getAuth: GetAuthFn = (_request: any, _options: any) => { + return {} as any; + }; + + // Session token by default + expectTypeOf(getAuth(request)).toEqualTypeOf(); + + // Individual token types + expectTypeOf(getAuth(request, { acceptsToken: 'session_token' })).toEqualTypeOf(); + expectTypeOf(getAuth(request, { acceptsToken: 'api_key' })).toEqualTypeOf>(); + expectTypeOf(getAuth(request, { acceptsToken: 'machine_token' })).toEqualTypeOf>(); + expectTypeOf(getAuth(request, { acceptsToken: 'oauth_token' })).toEqualTypeOf>(); + + // Array of token types + expectTypeOf(getAuth(request, { acceptsToken: ['session_token', 'oauth_token'] })).toEqualTypeOf< + SessionAuthObject | MachineAuthObject<'oauth_token'> + >(); +}); diff --git a/packages/backend/src/tokens/types.ts b/packages/backend/src/tokens/types.ts index c87f1f3bc8b..30ec47eb5d8 100644 --- a/packages/backend/src/tokens/types.ts +++ b/packages/backend/src/tokens/types.ts @@ -163,8 +163,8 @@ export type InferAuthObjectFromTokenArray< > = SessionTokenType extends T[number] ? T[number] extends SessionTokenType ? SessionType - : SessionType | (MachineType & { tokenType: T[number] }) - : MachineType & { tokenType: T[number] }; + : SessionType | (MachineType & { tokenType: Exclude }) + : MachineType & { tokenType: Exclude }; /** * Infers auth object type from a single token type. @@ -174,11 +174,11 @@ export type InferAuthObjectFromToken< T extends TokenType, SessionType extends AuthObject, MachineType extends AuthObject, -> = T extends SessionTokenType ? SessionType : MachineType & { tokenType: T }; +> = T extends SessionTokenType ? SessionType : MachineType & { tokenType: Exclude }; export type SessionAuthObject = SignedInAuthObject | SignedOutAuthObject; export type MachineAuthObject = (AuthenticatedMachineObject | UnauthenticatedMachineObject) & { - tokenType: T; + tokenType: Exclude; }; type AuthOptions = PendingSessionOptions & { acceptsToken?: AuthenticateRequestOptions['acceptsToken'] }; From 3a617cda991c758f2f564515287c187095e6ba45 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 13:34:21 -0700 Subject: [PATCH 02/13] chore: add typechecking to vitest config --- packages/backend/package.json | 6 +++--- .../src/tokens/__tests__/{types.test-d.ts => types.test.ts} | 0 packages/backend/vitest.config.mts | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) rename packages/backend/src/tokens/__tests__/{types.test-d.ts => types.test.ts} (100%) diff --git a/packages/backend/package.json b/packages/backend/package.json index 6d9773ff53f..337bcce1ad4 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -98,9 +98,9 @@ "lint:publint": "publint", "publish:local": "pnpm yalc push --replace --sig", "test": "run-s test:node test:edge-runtime test:cloudflare-miniflare", - "test:cloudflare-miniflare": "vitest run --typecheck --environment miniflare", - "test:edge-runtime": "vitest run --typecheck --environment edge-runtime", - "test:node": "vitest run --typecheck --environment node", + "test:cloudflare-miniflare": "vitest run --environment miniflare", + "test:edge-runtime": "vitest run --environment edge-runtime", + "test:node": "vitest run --environment node", "test:watch": "run-s test:watch:node test:watch:edge-runtime test:watch:cloudflare-miniflare", "test:watch:cloudflare-miniflare": "vitest watch --environment miniflare", "test:watch:edge-runtime": "vitest watch --environment edge-runtime", diff --git a/packages/backend/src/tokens/__tests__/types.test-d.ts b/packages/backend/src/tokens/__tests__/types.test.ts similarity index 100% rename from packages/backend/src/tokens/__tests__/types.test-d.ts rename to packages/backend/src/tokens/__tests__/types.test.ts diff --git a/packages/backend/vitest.config.mts b/packages/backend/vitest.config.mts index c4904416012..c690ee913f2 100644 --- a/packages/backend/vitest.config.mts +++ b/packages/backend/vitest.config.mts @@ -3,6 +3,10 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ plugins: [], test: { + typecheck: { + enabled: true, + include: ['**/*.test.ts'], + }, coverage: { provider: 'v8', }, From b11cb7d7a32e5550f5d9812796c4c252723758bb Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Fri, 6 Jun 2025 13:36:28 -0700 Subject: [PATCH 03/13] chore: add placeholder changeset --- .changeset/ten-shirts-double.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changeset/ten-shirts-double.md diff --git a/.changeset/ten-shirts-double.md b/.changeset/ten-shirts-double.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/ten-shirts-double.md @@ -0,0 +1,2 @@ +--- +--- From 35bda1844edea4920385eadec330dee9a8217abd Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 13:48:53 -0700 Subject: [PATCH 04/13] chore: add any token type test case --- packages/backend/src/tokens/__tests__/types.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend/src/tokens/__tests__/types.test.ts b/packages/backend/src/tokens/__tests__/types.test.ts index 3f834c9df92..fc09013d84b 100644 --- a/packages/backend/src/tokens/__tests__/types.test.ts +++ b/packages/backend/src/tokens/__tests__/types.test.ts @@ -1,5 +1,6 @@ import { expectTypeOf, test } from 'vitest'; +import type { AuthObject } from '../authObjects'; import type { GetAuthFn, MachineAuthObject, SessionAuthObject } from '../types'; test('infers the correct AuthObject type for each accepted token type', () => { @@ -23,4 +24,7 @@ test('infers the correct AuthObject type for each accepted token type', () => { expectTypeOf(getAuth(request, { acceptsToken: ['session_token', 'oauth_token'] })).toEqualTypeOf< SessionAuthObject | MachineAuthObject<'oauth_token'> >(); + + // Any token type + expectTypeOf(getAuth(request, { acceptsToken: 'any' })).toEqualTypeOf(); }); From cbb6080a05ff60f0fa3dfd0ca9ab97da05e306c3 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 13:56:10 -0700 Subject: [PATCH 05/13] chore: move auth object types outside of internal --- packages/backend/src/index.ts | 1 + packages/backend/src/internal.ts | 2 -- packages/nextjs/src/app-router/server/auth.ts | 4 +--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index eadfe571e51..2b33d227388 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -162,3 +162,4 @@ export type { * Auth objects */ export type { AuthObject } from './tokens/authObjects'; +export type { SessionAuthObject, MachineAuthObject } from './tokens/types'; diff --git a/packages/backend/src/internal.ts b/packages/backend/src/internal.ts index fc729046e19..4f176cc0489 100644 --- a/packages/backend/src/internal.ts +++ b/packages/backend/src/internal.ts @@ -12,8 +12,6 @@ export type { OrganizationSyncOptions, InferAuthObjectFromToken, InferAuthObjectFromTokenArray, - SessionAuthObject, - MachineAuthObject, GetAuthFn, } from './tokens/types'; diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 74ea1ff9051..5e28a79c441 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -1,11 +1,9 @@ -import type { AuthObject } from '@clerk/backend'; +import type { AuthObject, MachineAuthObject, SessionAuthObject } from '@clerk/backend'; import type { AuthenticateRequestOptions, InferAuthObjectFromToken, InferAuthObjectFromTokenArray, - MachineAuthObject, RedirectFun, - SessionAuthObject, } from '@clerk/backend/internal'; import { constants, createClerkRequest, createRedirect, TokenType } from '@clerk/backend/internal'; import type { PendingSessionOptions } from '@clerk/types'; From 14bb7f10645772f919f1f21cf753dfab7bc592fb Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 14:08:17 -0700 Subject: [PATCH 06/13] chore: clean up --- packages/backend/src/tokens/types.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/tokens/types.ts b/packages/backend/src/tokens/types.ts index 30ec47eb5d8..68032219396 100644 --- a/packages/backend/src/tokens/types.ts +++ b/packages/backend/src/tokens/types.ts @@ -177,7 +177,10 @@ export type InferAuthObjectFromToken< > = T extends SessionTokenType ? SessionType : MachineType & { tokenType: Exclude }; export type SessionAuthObject = SignedInAuthObject | SignedOutAuthObject; -export type MachineAuthObject = (AuthenticatedMachineObject | UnauthenticatedMachineObject) & { +export type MachineAuthObject> = ( + | AuthenticatedMachineObject + | UnauthenticatedMachineObject +) & { tokenType: Exclude; }; From 4326028a22dfde32a9995f842009330caebbb898 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 14:53:13 -0700 Subject: [PATCH 07/13] fix types --- packages/backend/src/tokens/types.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/tokens/types.ts b/packages/backend/src/tokens/types.ts index 68032219396..1a4baa68db7 100644 --- a/packages/backend/src/tokens/types.ts +++ b/packages/backend/src/tokens/types.ts @@ -202,7 +202,10 @@ export interface GetAuthFn ( req: RequestType, options: AuthOptions & { acceptsToken: T }, - ): MaybePromise>, ReturnsPromise>; + ): MaybePromise< + InferAuthObjectFromTokenArray>>, + ReturnsPromise + >; /** * @example @@ -211,7 +214,10 @@ export interface GetAuthFn ( req: RequestType, options: AuthOptions & { acceptsToken: T }, - ): MaybePromise>, ReturnsPromise>; + ): MaybePromise< + InferAuthObjectFromToken>>, + ReturnsPromise + >; /** * @example From c96232f9aa97c28cc98026926c608f63ee7b42e4 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 15:33:05 -0700 Subject: [PATCH 08/13] chore: add more type tests --- .../src/tokens/__tests__/types.test.ts | 66 ++++++++++++++----- packages/backend/src/tokens/types.ts | 9 +-- packages/nextjs/src/app-router/server/auth.ts | 13 +++- 3 files changed, 65 insertions(+), 23 deletions(-) diff --git a/packages/backend/src/tokens/__tests__/types.test.ts b/packages/backend/src/tokens/__tests__/types.test.ts index fc09013d84b..010357fc840 100644 --- a/packages/backend/src/tokens/__tests__/types.test.ts +++ b/packages/backend/src/tokens/__tests__/types.test.ts @@ -1,30 +1,66 @@ -import { expectTypeOf, test } from 'vitest'; +import { assertType, test } from 'vitest'; import type { AuthObject } from '../authObjects'; import type { GetAuthFn, MachineAuthObject, SessionAuthObject } from '../types'; +// Across our SDKs, we have a getAuth() function +const getAuth: GetAuthFn = (_request: any, _options: any) => { + return {} as any; +}; + test('infers the correct AuthObject type for each accepted token type', () => { const request = new Request('https://example.com'); - // Across our SDKs, we have a getAuth() function - const getAuth: GetAuthFn = (_request: any, _options: any) => { - return {} as any; - }; - // Session token by default - expectTypeOf(getAuth(request)).toEqualTypeOf(); + assertType(getAuth(request)); // Individual token types - expectTypeOf(getAuth(request, { acceptsToken: 'session_token' })).toEqualTypeOf(); - expectTypeOf(getAuth(request, { acceptsToken: 'api_key' })).toEqualTypeOf>(); - expectTypeOf(getAuth(request, { acceptsToken: 'machine_token' })).toEqualTypeOf>(); - expectTypeOf(getAuth(request, { acceptsToken: 'oauth_token' })).toEqualTypeOf>(); + assertType(getAuth(request, { acceptsToken: 'session_token' })); + assertType>(getAuth(request, { acceptsToken: 'api_key' })); + assertType>(getAuth(request, { acceptsToken: 'machine_token' })); + assertType>(getAuth(request, { acceptsToken: 'oauth_token' })); // Array of token types - expectTypeOf(getAuth(request, { acceptsToken: ['session_token', 'oauth_token'] })).toEqualTypeOf< - SessionAuthObject | MachineAuthObject<'oauth_token'> - >(); + assertType>( + getAuth(request, { acceptsToken: ['session_token', 'machine_token'] }), + ); + assertType>( + getAuth(request, { acceptsToken: ['machine_token', 'oauth_token'] }), + ); // Any token type - expectTypeOf(getAuth(request, { acceptsToken: 'any' })).toEqualTypeOf(); + assertType(getAuth(request, { acceptsToken: 'any' })); +}); + +test('verifies correct properties exist for each token type', () => { + const request = new Request('https://example.com'); + + // Session token should have userId + const sessionAuth = getAuth(request, { acceptsToken: 'session_token' }); + assertType(sessionAuth.userId); + + // All machine tokens should have id and subject + const apiKeyAuth = getAuth(request, { acceptsToken: 'api_key' }); + const machineTokenAuth = getAuth(request, { acceptsToken: 'machine_token' }); + const oauthTokenAuth = getAuth(request, { acceptsToken: 'oauth_token' }); + + assertType(apiKeyAuth.id); + assertType(machineTokenAuth.id); + assertType(oauthTokenAuth.id); + assertType(apiKeyAuth.subject); + assertType(machineTokenAuth.subject); + assertType(oauthTokenAuth.subject); + + // Only api_key and machine_token should have name and claims + assertType(apiKeyAuth.name); + assertType | null>(apiKeyAuth.claims); + + assertType(machineTokenAuth.name); + assertType | null>(machineTokenAuth.claims); + + // oauth_token should NOT have name and claims + // @ts-expect-error oauth_token does not have name property + void oauthTokenAuth.name; + // @ts-expect-error oauth_token does not have claims property + void oauthTokenAuth.claims; }); diff --git a/packages/backend/src/tokens/types.ts b/packages/backend/src/tokens/types.ts index 1a4baa68db7..badda7d18f3 100644 --- a/packages/backend/src/tokens/types.ts +++ b/packages/backend/src/tokens/types.ts @@ -177,12 +177,9 @@ export type InferAuthObjectFromToken< > = T extends SessionTokenType ? SessionType : MachineType & { tokenType: Exclude }; export type SessionAuthObject = SignedInAuthObject | SignedOutAuthObject; -export type MachineAuthObject> = ( - | AuthenticatedMachineObject - | UnauthenticatedMachineObject -) & { - tokenType: Exclude; -}; +export type MachineAuthObject> = T extends any + ? AuthenticatedMachineObject | UnauthenticatedMachineObject + : never; type AuthOptions = PendingSessionOptions & { acceptsToken?: AuthenticateRequestOptions['acceptsToken'] }; diff --git a/packages/nextjs/src/app-router/server/auth.ts b/packages/nextjs/src/app-router/server/auth.ts index 5e28a79c441..ec5b151f7ee 100644 --- a/packages/nextjs/src/app-router/server/auth.ts +++ b/packages/nextjs/src/app-router/server/auth.ts @@ -4,6 +4,7 @@ import type { InferAuthObjectFromToken, InferAuthObjectFromTokenArray, RedirectFun, + SessionTokenType, } from '@clerk/backend/internal'; import { constants, createClerkRequest, createRedirect, TokenType } from '@clerk/backend/internal'; import type { PendingSessionOptions } from '@clerk/types'; @@ -54,7 +55,13 @@ export interface AuthFn> { */ ( options: AuthOptions & { acceptsToken: T }, - ): Promise, MachineAuthObject>>; + ): Promise< + InferAuthObjectFromTokenArray< + T, + SessionAuthWithRedirect, + MachineAuthObject> + > + >; /** * @example @@ -62,7 +69,9 @@ export interface AuthFn> { */ ( options: AuthOptions & { acceptsToken: T }, - ): Promise, MachineAuthObject>>; + ): Promise< + InferAuthObjectFromToken, MachineAuthObject>> + >; /** * @example From 3903e93c85ec9eec08b97634983b10e2b58c053f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 15:49:15 -0700 Subject: [PATCH 09/13] chore: rename test file name --- .../{types.test.ts => getAuth.test-d.ts} | 41 ++++++++++++++++ packages/backend/src/tokens/authObjects.ts | 48 ++++++++++--------- 2 files changed, 67 insertions(+), 22 deletions(-) rename packages/backend/src/tokens/__tests__/{types.test.ts => getAuth.test-d.ts} (60%) diff --git a/packages/backend/src/tokens/__tests__/types.test.ts b/packages/backend/src/tokens/__tests__/getAuth.test-d.ts similarity index 60% rename from packages/backend/src/tokens/__tests__/types.test.ts rename to packages/backend/src/tokens/__tests__/getAuth.test-d.ts index 010357fc840..ec38dc42ffc 100644 --- a/packages/backend/src/tokens/__tests__/types.test.ts +++ b/packages/backend/src/tokens/__tests__/getAuth.test-d.ts @@ -64,3 +64,44 @@ test('verifies correct properties exist for each token type', () => { // @ts-expect-error oauth_token does not have claims property void oauthTokenAuth.claims; }); + +test('verifies discriminated union works correctly with acceptsToken: any', () => { + const request = new Request('https://example.com'); + + const auth = getAuth(request, { acceptsToken: 'any' }); + + if (auth.tokenType === 'session_token') { + // Should be SessionAuthObject - has userId + assertType(auth.userId); + // Should NOT have machine token properties + // @ts-expect-error session_token does not have id property + void auth.id; + } else if (auth.tokenType === 'api_key') { + // Should be AuthenticatedMachineObject<'api_key'> - has id, name, claims + assertType(auth.id); + assertType(auth.name); + assertType | null>(auth.claims); + // Should NOT have session token properties + // @ts-expect-error api_key does not have userId property + void auth.userId; + } else if (auth.tokenType === 'machine_token') { + // Should be AuthenticatedMachineObject<'machine_token'> - has id, name, claims + assertType(auth.id); + assertType(auth.name); + assertType | null>(auth.claims); + // Should NOT have session token properties + // @ts-expect-error machine_token does not have userId property + void auth.userId; + } else if (auth.tokenType === 'oauth_token') { + // Should be AuthenticatedMachineObject<'oauth_token'> - has id but NOT name/claims + assertType(auth.id); + // Should NOT have name or claims + // @ts-expect-error oauth_token does not have name property + void auth.name; + // @ts-expect-error oauth_token does not have claims property + void auth.claims; + // Should NOT have session token properties + // @ts-expect-error oauth_token does not have userId property + void auth.userId; + } +}); diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index 97135c03865..7b3a1d87cc6 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -105,28 +105,32 @@ type MachineObjectExtendedProperties = { /** * @internal */ -export type AuthenticatedMachineObject = { - id: string; - subject: string; - scopes: string[]; - getToken: () => Promise; - has: CheckAuthorizationFromSessionClaims; - debug: AuthObjectDebug; - tokenType: T; -} & MachineObjectExtendedProperties[T]; +export type AuthenticatedMachineObject = T extends any + ? { + id: string; + subject: string; + scopes: string[]; + getToken: () => Promise; + has: CheckAuthorizationFromSessionClaims; + debug: AuthObjectDebug; + tokenType: T; + } & MachineObjectExtendedProperties[T] + : never; /** * @internal */ -export type UnauthenticatedMachineObject = { - id: null; - subject: null; - scopes: null; - getToken: () => Promise; - has: CheckAuthorizationFromSessionClaims; - debug: AuthObjectDebug; - tokenType: T; -} & MachineObjectExtendedProperties[T]; +export type UnauthenticatedMachineObject = T extends any + ? { + id: null; + subject: null; + scopes: null; + getToken: () => Promise; + has: CheckAuthorizationFromSessionClaims; + debug: AuthObjectDebug; + tokenType: T; + } & MachineObjectExtendedProperties[T] + : never; /** * @interface @@ -243,7 +247,7 @@ export function authenticatedMachineObject( name: result.name, claims: result.claims, scopes: result.scopes, - }; + } as unknown as AuthenticatedMachineObject; } case TokenType.MachineToken: { const result = verificationResult as MachineToken; @@ -253,7 +257,7 @@ export function authenticatedMachineObject( name: result.name, claims: result.claims, scopes: result.scopes, - }; + } as unknown as AuthenticatedMachineObject; } case TokenType.OAuthToken: { return { @@ -290,7 +294,7 @@ export function unauthenticatedMachineObject( tokenType, name: null, claims: null, - }; + } as unknown as UnauthenticatedMachineObject; } case TokenType.MachineToken: { return { @@ -298,7 +302,7 @@ export function unauthenticatedMachineObject( tokenType, name: null, claims: null, - }; + } as unknown as UnauthenticatedMachineObject; } case TokenType.OAuthToken: { return { From 46769e051270852b7a95605a902551791bc33b38 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 15:54:13 -0700 Subject: [PATCH 10/13] chore: more type doc explanations --- packages/backend/src/tokens/authObjects.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index 7b3a1d87cc6..410aef1e77d 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -104,6 +104,11 @@ type MachineObjectExtendedProperties = { /** * @internal + * + * Uses `T extends any` to create a distributive conditional type. + * This ensures that union types like `'api_key' | 'oauth_token'` are processed + * individually, creating proper discriminated unions where each token type + * gets its own distinct properties (e.g., oauth_token won't have claims). */ export type AuthenticatedMachineObject = T extends any ? { @@ -119,6 +124,11 @@ export type AuthenticatedMachineObject = T extends any ? { From 0059d73ca49d9be227bf660ac3303492344089a6 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 16:12:06 -0700 Subject: [PATCH 11/13] chore: add any type to protect --- packages/nextjs/src/server/protect.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/nextjs/src/server/protect.ts b/packages/nextjs/src/server/protect.ts index bdd73ce85ec..cfb0dea5628 100644 --- a/packages/nextjs/src/server/protect.ts +++ b/packages/nextjs/src/server/protect.ts @@ -73,6 +73,12 @@ export interface AuthProtect { options?: AuthProtectOptions & { token: T }, ): Promise>; + /** + * @example + * auth.protect({ token: 'any' }); + */ + (options?: AuthProtectOptions & { token: 'any' }): Promise; + /** * @example * auth.protect(); From e19aa488e84c872c76588e03f93ee191deca1260 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 6 Jun 2025 16:14:26 -0700 Subject: [PATCH 12/13] chore: add changeset --- .changeset/social-carrots-melt.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/social-carrots-melt.md diff --git a/.changeset/social-carrots-melt.md b/.changeset/social-carrots-melt.md new file mode 100644 index 00000000000..b3effe5a915 --- /dev/null +++ b/.changeset/social-carrots-melt.md @@ -0,0 +1,6 @@ +--- +'@clerk/backend': patch +'@clerk/nextjs': patch +--- + +Resolve machine token property mixing in discriminated unions \ No newline at end of file From 2088ba183c7720ef2317cdb11147980486da36f9 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Fri, 6 Jun 2025 16:14:59 -0700 Subject: [PATCH 13/13] Delete .changeset/ten-shirts-double.md --- .changeset/ten-shirts-double.md | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .changeset/ten-shirts-double.md diff --git a/.changeset/ten-shirts-double.md b/.changeset/ten-shirts-double.md deleted file mode 100644 index a845151cc84..00000000000 --- a/.changeset/ten-shirts-double.md +++ /dev/null @@ -1,2 +0,0 @@ ---- ----