-
Notifications
You must be signed in to change notification settings - Fork 460
Expand file tree
/
Copy pathjwt-client.ts
More file actions
104 lines (96 loc) · 3.33 KB
/
Copy pathjwt-client.ts
File metadata and controls
104 lines (96 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { __experimental_JWTPayloadToAuthObjectProperties } from '@clerk/shared/jwtPayloadParser';
import type {
ClientJSON,
OrganizationMembershipJSON,
PartialWithClerkResource,
PublicUserDataJSON,
SessionJSON,
TokenJSON,
UserJSON,
} from '@clerk/shared/types';
import { Token } from './resources';
import { Client } from './resources/Client';
/**
* Create a new client instance from a jwt.
* The caller is responsible for reading the jwt from the `__session` cookie.
*/
export function createClientFromJwt(jwt: string | undefined | null): Client {
// Use `Token` class to parse the JWT token
let token: Token | null;
try {
token = new Token({
jwt: jwt || '',
object: 'token',
// @ts-expect-error - ts is not happy about it, but this is allowed
id: undefined,
});
} catch {
// If the token is invalid, return null
token = null;
}
// Clean up singleton instance
Client.clearInstance();
if (!token?.jwt) {
return Client.getOrCreateInstance({
object: 'client',
last_active_session_id: null,
id: 'client_init',
sessions: [],
} as unknown as ClientJSON);
}
const { sessionId, userId, orgId, orgRole, orgPermissions, orgSlug, factorVerificationAge } =
__experimental_JWTPayloadToAuthObjectProperties(token.jwt.claims);
// TODO(jwt-v2): when JWT version 2 is available, we should revise org permissions
const defaultClient = {
object: 'client',
last_active_session_id: sessionId,
id: 'client_init',
sessions: [
{
object: 'session',
id: sessionId,
status: 'active',
last_active_organization_id: orgId || null,
// @ts-expect-error - ts is not happy about `id:undefined`, but this is allowed and expected
last_active_token: {
id: undefined,
object: 'token',
jwt,
} as TokenJSON,
factor_verification_age: factorVerificationAge || null,
public_user_data: {
user_id: userId,
} as PublicUserDataJSON,
user: {
object: 'user',
id: userId,
// Epoch 1, not 0: unixEpochToDate treats 0 as "now", and a "now" timestamp makes
// memoizeListenerCallback consider this stub newer than the real user fetched later,
// so listeners would keep rendering the stub after the full client arrives.
updated_at: 1,
organization_memberships:
orgId && orgSlug && orgRole
? [
{
object: 'organization_membership',
id: orgId,
role: orgRole,
permissions: orgPermissions || [],
organization: {
object: 'organization',
id: orgId,
// Use slug as name for the organization, since name is not available in the token.
name: orgSlug,
slug: orgSlug,
members_count: 1,
max_allowed_memberships: 1,
},
} as PartialWithClerkResource<OrganizationMembershipJSON>,
]
: [],
} as PartialWithClerkResource<UserJSON>,
} as PartialWithClerkResource<SessionJSON>,
],
} as ClientJSON;
return Client.getOrCreateInstance(defaultClient);
}