Skip to content

Commit 4d9f1ee

Browse files
authored
chore(backend,react,vue,shared,types): Derive session status from server-side state (#5447)
1 parent 2eca125 commit 4d9f1ee

File tree

9 files changed

+49
-5
lines changed

9 files changed

+49
-5
lines changed

.changeset/twelve-bees-cough.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@clerk/backend': patch
3+
'@clerk/shared': patch
4+
'@clerk/clerk-react': patch
5+
'@clerk/vue': patch
6+
'@clerk/types': patch
7+
---
8+
9+
Derive session status from server-side state

packages/backend/src/tokens/authObjects.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
OrganizationCustomRoleKey,
88
ServerGetToken,
99
ServerGetTokenOptions,
10+
SessionStatusClaim,
1011
} from '@clerk/types';
1112

1213
import type { CreateBackendApiOptions } from '../api';
@@ -29,6 +30,7 @@ export type SignedInAuthObjectOptions = CreateBackendApiOptions & {
2930
export type SignedInAuthObject = {
3031
sessionClaims: JwtPayload;
3132
sessionId: string;
33+
sessionStatus: SessionStatusClaim | null;
3234
actor: ActClaim | undefined;
3335
userId: string;
3436
orgId: string | undefined;
@@ -52,6 +54,7 @@ export type SignedInAuthObject = {
5254
export type SignedOutAuthObject = {
5355
sessionClaims: null;
5456
sessionId: null;
57+
sessionStatus: null;
5558
actor: null;
5659
userId: null;
5760
orgId: null;
@@ -100,6 +103,7 @@ export function signedInAuthObject(
100103
org_permissions: orgPermissions,
101104
sub: userId,
102105
fva,
106+
sts,
103107
} = sessionClaims;
104108
const apiClient = createBackendApiClient(authenticateContext);
105109
const getToken = createGetToken({
@@ -111,10 +115,14 @@ export function signedInAuthObject(
111115
// fva can be undefined for instances that have not opt-in
112116
const factorVerificationAge = fva ?? null;
113117

118+
// sts can be undefined for instances that have not opt-in
119+
const sessionStatus = sts ?? null;
120+
114121
return {
115122
actor,
116123
sessionClaims,
117124
sessionId,
125+
sessionStatus,
118126
userId,
119127
orgId,
120128
orgRole,
@@ -134,6 +142,7 @@ export function signedOutAuthObject(debugData?: AuthObjectDebugData): SignedOutA
134142
return {
135143
sessionClaims: null,
136144
sessionId: null,
145+
sessionStatus: null,
137146
userId: null,
138147
actor: null,
139148
orgId: null,

packages/react/src/contexts/AuthContext.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { createContextAndHook } from '@clerk/shared/react';
2-
import type { ActClaim, OrganizationCustomPermissionKey, OrganizationCustomRoleKey } from '@clerk/types';
2+
import type {
3+
ActClaim,
4+
OrganizationCustomPermissionKey,
5+
OrganizationCustomRoleKey,
6+
SessionStatusClaim,
7+
} from '@clerk/types';
38

49
export type AuthContextValue = {
510
userId: string | null | undefined;
611
sessionId: string | null | undefined;
12+
sessionStatus: SessionStatusClaim | null | undefined;
713
actor: ActClaim | null | undefined;
814
orgId: string | null | undefined;
915
orgRole: OrganizationCustomRoleKey | null | undefined;

packages/react/src/contexts/ClerkContextProvider.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export function ClerkContextProvider(props: ClerkContextProvider) {
3737

3838
const {
3939
sessionId,
40+
sessionStatus,
4041
session,
4142
userId,
4243
user,
@@ -52,6 +53,7 @@ export function ClerkContextProvider(props: ClerkContextProvider) {
5253
const authCtx = React.useMemo(() => {
5354
const value = {
5455
sessionId,
56+
sessionStatus,
5557
userId,
5658
actor,
5759
orgId,
@@ -61,7 +63,7 @@ export function ClerkContextProvider(props: ClerkContextProvider) {
6163
factorVerificationAge,
6264
};
6365
return { value };
64-
}, [sessionId, userId, actor, orgId, orgRole, orgSlug, factorVerificationAge]);
66+
}, [sessionId, sessionStatus, userId, actor, orgId, orgRole, orgSlug, factorVerificationAge]);
6567
const sessionCtx = React.useMemo(() => ({ value: session }), [sessionId, session]);
6668
const userCtx = React.useMemo(() => ({ value: user }), [userId, user]);
6769
const organizationCtx = React.useMemo(() => {

packages/shared/src/deriveState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const deriveFromSsrInitialState = (initialState: InitialState) => {
2222
const userId = initialState.userId;
2323
const user = initialState.user as UserResource;
2424
const sessionId = initialState.sessionId;
25+
const sessionStatus = initialState.sessionStatus;
2526
const session = initialState.session as SignedInSessionResource;
2627
const organization = initialState.organization as OrganizationResource;
2728
const orgId = initialState.orgId;
@@ -36,6 +37,7 @@ const deriveFromSsrInitialState = (initialState: InitialState) => {
3637
user,
3738
sessionId,
3839
session,
40+
sessionStatus,
3941
organization,
4042
orgId,
4143
orgRole,
@@ -51,6 +53,7 @@ const deriveFromClientSideState = (state: Resources) => {
5153
const user = state.user;
5254
const sessionId: string | null | undefined = state.session ? state.session.id : state.session;
5355
const session = state.session;
56+
const sessionStatus = state.session?.status;
5457
const factorVerificationAge: [number, number] | null = state.session ? state.session.factorVerificationAge : null;
5558
const actor = session?.actor;
5659
const organization = state.organization;
@@ -67,6 +70,7 @@ const deriveFromClientSideState = (state: Resources) => {
6770
user,
6871
sessionId,
6972
session,
73+
sessionStatus,
7074
organization,
7175
orgId,
7276
orgRole,

packages/types/src/jwtv2.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey } from './organizationMembership';
2+
import type { SessionStatus } from './session';
23

34
export interface Jwt {
45
header: JwtHeader;
@@ -108,6 +109,11 @@ export interface JwtPayload extends CustomJwtSessionClaims {
108109
*/
109110
fva?: [fistFactorAge: number, secondFactorAge: number];
110111

112+
/**
113+
* Session status
114+
*/
115+
sts?: SessionStatusClaim;
116+
111117
/**
112118
* Any other JWT Claim Set member.
113119
*/
@@ -122,3 +128,8 @@ export interface ActClaim {
122128
sub: string;
123129
[x: string]: unknown;
124130
}
131+
132+
/**
133+
* Session status
134+
*/
135+
export type SessionStatusClaim = Extract<SessionStatus, 'active' | 'pending'>;

packages/types/src/ssr.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ActClaim, JwtPayload } from './jwtv2';
1+
import type { ActClaim, JwtPayload, SessionStatusClaim } from './jwtv2';
22
import type { OrganizationResource } from './organization';
33
import type { OrganizationCustomPermissionKey, OrganizationCustomRoleKey } from './organizationMembership';
44
import type { SessionResource } from './session';
@@ -11,6 +11,7 @@ export type ServerGetToken = (options?: ServerGetTokenOptions) => Promise<string
1111
export type InitialState = Serializable<{
1212
sessionClaims: JwtPayload;
1313
sessionId: string | undefined;
14+
sessionStatus: SessionStatusClaim;
1415
session: SessionResource | undefined;
1516
actor: ActClaim | undefined;
1617
userId: string | undefined;

packages/vue/src/plugin.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ export const clerkPlugin: Plugin = {
6868
const derivedState = computed(() => deriveState(loaded.value, resources.value, initialState));
6969

7070
const authCtx = computed(() => {
71-
const { sessionId, userId, orgId, actor, orgRole, orgSlug, orgPermissions } = derivedState.value;
72-
return { sessionId, userId, actor, orgId, orgRole, orgSlug, orgPermissions };
71+
const { sessionId, userId, orgId, actor, orgRole, orgSlug, orgPermissions, sessionStatus } = derivedState.value;
72+
return { sessionId, userId, actor, orgId, orgRole, orgSlug, orgPermissions, sessionStatus };
7373
});
7474
const clientCtx = computed(() => resources.value.client);
7575
const userCtx = computed(() => derivedState.value.user);

packages/vue/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
OrganizationCustomPermissionKey,
99
OrganizationCustomRoleKey,
1010
OrganizationResource,
11+
SessionStatusClaim,
1112
SignedInSessionResource,
1213
UserResource,
1314
Without,
@@ -20,6 +21,7 @@ export interface VueClerkInjectionKeyType {
2021
userId: string | null | undefined;
2122
sessionId: string | null | undefined;
2223
actor: ActClaim | null | undefined;
24+
sessionStatus: SessionStatusClaim | null | undefined;
2325
orgId: string | null | undefined;
2426
orgRole: OrganizationCustomRoleKey | null | undefined;
2527
orgSlug: string | null | undefined;

0 commit comments

Comments
 (0)