-
Notifications
You must be signed in to change notification settings - Fork 455
Expand file tree
/
Copy pathnormalize-session.ts
More file actions
136 lines (116 loc) · 2.95 KB
/
normalize-session.ts
File metadata and controls
136 lines (116 loc) · 2.95 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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { JWTDecryptResult } from "jose";
import { SessionData } from "../../types/index.js";
export const LEGACY_COOKIE_NAME = "appSession";
/**
* Key-value store for the user's claims.
*/
interface LegacyClaims {
[key: string]: any;
}
/**
* The user's session.
*/
export class LegacySession {
/**
* Any of the claims from the `id_token`.
*/
user: LegacyClaims;
/**
* The ID token.
*/
idToken?: string | undefined;
/**
* The access token.
*/
accessToken?: string | undefined;
/**
* The access token scopes.
*/
accessTokenScope?: string | undefined;
/**
* The expiration of the access token.
*/
accessTokenExpiresAt?: number;
/**
* The refresh token, which is used to request a new access token.
*
* **IMPORTANT** You need to request the `offline_access` scope on login to get a refresh token
* from Auth0.
*/
refreshToken?: string | undefined;
[key: string]: any;
constructor(user: LegacyClaims) {
this.user = user;
}
}
/**
* The legacy headers of the session.
*/
interface LegacyHeaders {
/**
* Timestamp (in secs) when the session was created.
*/
iat: number;
/**
* Timestamp (in secs) when the session was last touched.
*/
uat: number;
/**
* Timestamp (in secs) when the session expires.
*/
exp: number;
}
export interface LegacySessionPayload {
/**
* The session header.
*/
header: LegacyHeaders;
/**
* The session data.
*/
data: LegacySession;
}
export function normalizeStatelessSession(
sessionCookie: JWTDecryptResult<LegacySessionPayload | SessionData>
) {
// if the session cookie has an `iat` claim in the protected header, it's a legacy cookie
// otherwise, it's the new session cookie format and no transformation is needed
if (sessionCookie.protectedHeader.iat) {
const legacySession = sessionCookie as JWTDecryptResult<LegacySession>;
return convertFromLegacy(
legacySession.protectedHeader,
legacySession.payload
);
}
return sessionCookie.payload as SessionData;
}
export function normalizeStatefulSession(
sessionData: SessionData | LegacySessionPayload
) {
if ((sessionData.header as LegacyHeaders | undefined)?.iat) {
const legacySession = sessionData as LegacySessionPayload;
return convertFromLegacy(legacySession.header, legacySession.data);
}
return sessionData as SessionData;
}
function convertFromLegacy(
header:
| LegacyHeaders
| JWTDecryptResult<LegacySessionPayload>["protectedHeader"],
session: LegacySession
) {
const userClaims = session.user as LegacyClaims;
return {
user: userClaims,
tokenSet: {
accessToken: (session.accessToken as string) ?? undefined,
scope: session.accessTokenScope as string | undefined,
refreshToken: session.refreshToken as string | undefined,
expiresAt: session.accessTokenExpiresAt as number
},
internal: {
sid: userClaims.sid,
createdAt: header.iat
}
} as SessionData;
}