diff --git a/.changeset/moody-clocks-repeat.md b/.changeset/moody-clocks-repeat.md new file mode 100644 index 00000000000..cbda9da8db4 --- /dev/null +++ b/.changeset/moody-clocks-repeat.md @@ -0,0 +1,8 @@ +--- +"@clerk/clerk-js": patch +"@clerk/backend": patch +"@clerk/clerk-react": patch +"@clerk/types": patch +--- + +Update type of `__experimental_factorVerificationAge` to be `[number, number] | null`. diff --git a/packages/backend/src/tokens/authObjects.ts b/packages/backend/src/tokens/authObjects.ts index e64abce784c..84e00271c41 100644 --- a/packages/backend/src/tokens/authObjects.ts +++ b/packages/backend/src/tokens/authObjects.ts @@ -40,7 +40,7 @@ export type SignedInAuthObject = { * [fistFactorAge, secondFactorAge] * @experimental This API is experimental and may change at any moment. */ - __experimental_factorVerificationAge: [number | null, number | null]; + __experimental_factorVerificationAge: [number, number] | null; getToken: ServerGetToken; has: CheckAuthorizationWithCustomPermissions; debug: AuthObjectDebug; @@ -64,7 +64,7 @@ export type SignedOutAuthObject = { * [fistFactorAge, secondFactorAge] * @experimental This API is experimental and may change at any moment. */ - __experimental_factorVerificationAge: [null, null]; + __experimental_factorVerificationAge: null; getToken: ServerGetToken; has: CheckAuthorizationWithCustomPermissions; debug: AuthObjectDebug; @@ -100,7 +100,7 @@ export function signedInAuthObject( org_slug: orgSlug, org_permissions: orgPermissions, sub: userId, - fva: __experimental_factorVerificationAge, + fva, } = sessionClaims; const apiClient = createBackendApiClient(authenticateContext); const getToken = createGetToken({ @@ -109,6 +109,9 @@ export function signedInAuthObject( fetcher: async (...args) => (await apiClient.sessions.getToken(...args)).jwt, }); + // fva can be undefined for instances that have not opt-in + const __experimental_factorVerificationAge = fva ?? null; + return { actor, sessionClaims, @@ -138,7 +141,7 @@ export function signedOutAuthObject(debugData?: AuthObjectDebugData): SignedOutA orgRole: null, orgSlug: null, orgPermissions: null, - __experimental_factorVerificationAge: [null, null], + __experimental_factorVerificationAge: null, getToken: () => Promise.resolve(null), has: () => false, debug: createDebug(debugData), diff --git a/packages/clerk-js/src/core/resources/Session.ts b/packages/clerk-js/src/core/resources/Session.ts index 7a32e025a5e..3307d7bd981 100644 --- a/packages/clerk-js/src/core/resources/Session.ts +++ b/packages/clerk-js/src/core/resources/Session.ts @@ -39,7 +39,7 @@ export class Session extends BaseResource implements SessionResource { actor!: ActJWTClaim | null; user!: UserResource | null; publicUserData!: PublicUserData; - __experimental_factorVerificationAge: [number | null, number | null] = [null, null]; + __experimental_factorVerificationAge: [number, number] | null = null; expireAt!: Date; abandonAt!: Date; createdAt!: Date; diff --git a/packages/clerk-js/src/utils/memoizeStateListenerCallback.ts b/packages/clerk-js/src/utils/memoizeStateListenerCallback.ts index cfcac5aa57e..a48efc48397 100644 --- a/packages/clerk-js/src/utils/memoizeStateListenerCallback.ts +++ b/packages/clerk-js/src/utils/memoizeStateListenerCallback.ts @@ -51,10 +51,12 @@ function userMembershipsChanged(prev: UserResource, next: UserResource): boolean } function sessionFVAChanged(prev: SessionResource, next: SessionResource): boolean { - return ( - prev.__experimental_factorVerificationAge[0] !== next.__experimental_factorVerificationAge[0] || - prev.__experimental_factorVerificationAge[1] !== next.__experimental_factorVerificationAge[1] - ); + const prevFVA = prev.__experimental_factorVerificationAge; + const nextFVA = next.__experimental_factorVerificationAge; + if (prevFVA !== null && nextFVA !== null) { + return prevFVA[0] !== nextFVA[0] || prevFVA[1] !== nextFVA[1]; + } + return prevFVA !== nextFVA; } function sessionUserMembershipPermissionsChanged(prev: SessionResource, next: SessionResource): boolean { diff --git a/packages/react/src/contexts/AuthContext.ts b/packages/react/src/contexts/AuthContext.ts index 614afb57f15..a17cfb43dfb 100644 --- a/packages/react/src/contexts/AuthContext.ts +++ b/packages/react/src/contexts/AuthContext.ts @@ -9,5 +9,5 @@ export const [AuthContext, useAuthContext] = createContextAndHook<{ orgRole: OrganizationCustomRoleKey | null | undefined; orgSlug: string | null | undefined; orgPermissions: OrganizationCustomPermissionKey[] | null | undefined; - __experimental_factorVerificationAge: [number | null, number | null]; + __experimental_factorVerificationAge: [number, number] | null; }>('AuthContext'); diff --git a/packages/react/src/utils/deriveState.ts b/packages/react/src/utils/deriveState.ts index 86885405616..c301d471238 100644 --- a/packages/react/src/utils/deriveState.ts +++ b/packages/react/src/utils/deriveState.ts @@ -48,9 +48,9 @@ const deriveFromClientSideState = (state: Resources) => { const user = state.user; const sessionId: string | null | undefined = state.session ? state.session.id : state.session; const session = state.session; - const __experimental_factorVerificationAge: [number | null, number | null] = state.session + const __experimental_factorVerificationAge: [number, number] | null = state.session ? state.session.__experimental_factorVerificationAge - : [null, null]; + : null; const actor = session?.actor; const organization = state.organization; const orgId: string | null | undefined = state.organization ? state.organization.id : state.organization; diff --git a/packages/types/src/json.ts b/packages/types/src/json.ts index ab674ba6ea9..f01d00870df 100644 --- a/packages/types/src/json.ts +++ b/packages/types/src/json.ts @@ -110,7 +110,7 @@ export interface SessionJSON extends ClerkResourceJSON { * [fistFactorAge, secondFactorAge] * @experimental This API is experimental and may change at any moment. */ - factor_verification_age: [number | null, number | null]; + factor_verification_age: [number, number] | null; expire_at: number; abandon_at: number; last_active_at: number; diff --git a/packages/types/src/jwtv2.ts b/packages/types/src/jwtv2.ts index c76f25057a5..73ef4232f4d 100644 --- a/packages/types/src/jwtv2.ts +++ b/packages/types/src/jwtv2.ts @@ -107,7 +107,7 @@ export interface JwtPayload extends CustomJwtSessionClaims { * [fistFactorAge, secondFactorAge] * @experimental This API is experimental and may change at any moment. */ - fva: [number | null, number | null]; + fva?: [number, number]; /** * Any other JWT Claim Set member. diff --git a/packages/types/src/session.ts b/packages/types/src/session.ts index 43ed41bc88a..ab34ff39ccf 100644 --- a/packages/types/src/session.ts +++ b/packages/types/src/session.ts @@ -61,7 +61,7 @@ export interface SessionResource extends ClerkResource { * [fistFactorAge, secondFactorAge] * @experimental This API is experimental and may change at any moment. */ - __experimental_factorVerificationAge: [number | null, number | null]; + __experimental_factorVerificationAge: [number, number] | null; lastActiveToken: TokenResource | null; lastActiveOrganizationId: string | null; lastActiveAt: Date; diff --git a/packages/types/src/ssr.ts b/packages/types/src/ssr.ts index d215a283b9d..0f7773aa08b 100644 --- a/packages/types/src/ssr.ts +++ b/packages/types/src/ssr.ts @@ -20,5 +20,5 @@ export type InitialState = Serializable<{ orgSlug: string | undefined; orgPermissions: OrganizationCustomPermissionKey[] | undefined; organization: OrganizationResource | undefined; - __experimental_factorVerificationAge: [number | null, number | null]; + __experimental_factorVerificationAge: [number, number]; }>;