auth-vir 2.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -31,7 +31,7 @@ export type GetUserResult<DatabaseUser extends AnyObject> = {
|
|
|
31
31
|
*
|
|
32
32
|
* @category Internal
|
|
33
33
|
*/
|
|
34
|
-
export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId extends string | number,
|
|
34
|
+
export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId extends string | number, AssumedUserParams extends JsonCompatibleObject = EmptyObject, CsrfHeaderName extends string = AuthHeaderName.CsrfToken> = Readonly<{
|
|
35
35
|
/** The origin of your backend that is offering auth cookies. */
|
|
36
36
|
serviceOrigin: string;
|
|
37
37
|
/** Finds the relevant user from your own database. */
|
|
@@ -44,7 +44,7 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
|
|
|
44
44
|
* If this is set, we're attempting to load a database user for the purpose of assuming
|
|
45
45
|
* their user identity. Otherwise, this is `undefined`.
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
assumingUser: AssumedUserParams | undefined;
|
|
48
48
|
}) => MaybePromise<DatabaseUser | undefined | null>;
|
|
49
49
|
/**
|
|
50
50
|
* Get JWT keys produced by {@link generateNewJwtKeys}. Make sure that each time this is
|
|
@@ -67,11 +67,11 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
|
|
|
67
67
|
*/
|
|
68
68
|
assumeUser: {
|
|
69
69
|
/**
|
|
70
|
-
*
|
|
70
|
+
* Parse the assumed user header value.
|
|
71
71
|
*
|
|
72
72
|
* @see {@link AuthHeaderName}
|
|
73
73
|
*/
|
|
74
|
-
|
|
74
|
+
parseAssumedUserHeaderValue: (
|
|
75
75
|
/**
|
|
76
76
|
* The assumed user header value.
|
|
77
77
|
*
|
|
@@ -82,15 +82,12 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
|
|
|
82
82
|
userId: UserId;
|
|
83
83
|
} | undefined>;
|
|
84
84
|
/**
|
|
85
|
-
* Return `true` to allow the current user
|
|
86
|
-
*
|
|
87
|
-
* admin users.
|
|
85
|
+
* Return `true` to allow the current/original user to assume identities of other users.
|
|
86
|
+
* Return `false` to block it. It is recommended to only return `true` for admin users.
|
|
88
87
|
*
|
|
89
88
|
* @see {@link AuthHeaderName}
|
|
90
89
|
*/
|
|
91
|
-
canAssumeUser: (
|
|
92
|
-
userId: UserId;
|
|
93
|
-
}) => MaybePromise<boolean>;
|
|
90
|
+
canAssumeUser: (originalUser: DatabaseUser) => MaybePromise<boolean>;
|
|
94
91
|
};
|
|
95
92
|
/**
|
|
96
93
|
* This determines how long a cookie will be valid until it needs to be refreshed.
|
|
@@ -117,10 +114,10 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
|
|
|
117
114
|
* @category Auth : Host
|
|
118
115
|
* @category Client
|
|
119
116
|
*/
|
|
120
|
-
export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId extends string | number,
|
|
121
|
-
protected readonly config: BackendAuthClientConfig<DatabaseUser, UserId,
|
|
117
|
+
export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId extends string | number, AssumedUserParams extends AnyObject = EmptyObject, CsrfHeaderName extends string = AuthHeaderName.CsrfToken> {
|
|
118
|
+
protected readonly config: BackendAuthClientConfig<DatabaseUser, UserId, AssumedUserParams, CsrfHeaderName>;
|
|
122
119
|
protected cachedParsedJwtKeys: Record<string, Readonly<JwtKeys>>;
|
|
123
|
-
constructor(config: BackendAuthClientConfig<DatabaseUser, UserId,
|
|
120
|
+
constructor(config: BackendAuthClientConfig<DatabaseUser, UserId, AssumedUserParams, CsrfHeaderName>);
|
|
124
121
|
/** Get all the parameters used for cookie generation. */
|
|
125
122
|
protected getCookieParams({ isSignUpCookie, }: {
|
|
126
123
|
/**
|
|
@@ -132,9 +129,9 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
|
|
|
132
129
|
isSignUpCookie?: boolean | undefined;
|
|
133
130
|
}): Promise<Readonly<CookieParams>>;
|
|
134
131
|
/** Calls the provided `getUserFromDatabase` config. */
|
|
135
|
-
protected getDatabaseUser({ isSignUpCookie, userId,
|
|
132
|
+
protected getDatabaseUser({ isSignUpCookie, userId, assumingUser, }: {
|
|
136
133
|
userId: UserId | undefined;
|
|
137
|
-
|
|
134
|
+
assumingUser: AssumedUserParams | undefined;
|
|
138
135
|
isSignUpCookie: boolean;
|
|
139
136
|
}): Promise<undefined | DatabaseUser>;
|
|
140
137
|
/** Creates a `'cookie-set'` header to refresh the user's session cookie. */
|
|
@@ -142,8 +139,8 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
|
|
|
142
139
|
userIdResult: Readonly<UserIdResult<UserId>>;
|
|
143
140
|
}): Promise<OutgoingHttpHeaders | undefined>;
|
|
144
141
|
/** Reads the user's assumed user headers and, if configured, gets the assumed user. */
|
|
145
|
-
protected getAssumedUser({ headers,
|
|
146
|
-
|
|
142
|
+
protected getAssumedUser({ headers, user, }: {
|
|
143
|
+
user: DatabaseUser;
|
|
147
144
|
headers: IncomingHttpHeaders;
|
|
148
145
|
}): Promise<DatabaseUser | undefined>;
|
|
149
146
|
/** Securely extract a user from their request headers. */
|
|
@@ -31,12 +31,12 @@ export class BackendAuthClient {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
/** Calls the provided `getUserFromDatabase` config. */
|
|
34
|
-
async getDatabaseUser({ isSignUpCookie, userId,
|
|
34
|
+
async getDatabaseUser({ isSignUpCookie, userId, assumingUser, }) {
|
|
35
35
|
if (!userId) {
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
38
|
const authenticatedUser = await this.config.getUserFromDatabase({
|
|
39
|
-
|
|
39
|
+
assumingUser,
|
|
40
40
|
userId,
|
|
41
41
|
isSignUpCookie,
|
|
42
42
|
});
|
|
@@ -89,26 +89,22 @@ export class BackendAuthClient {
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
/** Reads the user's assumed user headers and, if configured, gets the assumed user. */
|
|
92
|
-
async getAssumedUser({ headers,
|
|
93
|
-
if (!
|
|
94
|
-
!this.config.assumeUser ||
|
|
95
|
-
!(await this.config.assumeUser.canAssumeUser({
|
|
96
|
-
userId: originalUserId,
|
|
97
|
-
}))) {
|
|
92
|
+
async getAssumedUser({ headers, user, }) {
|
|
93
|
+
if (!this.config.assumeUser || !(await this.config.assumeUser.canAssumeUser(user))) {
|
|
98
94
|
return undefined;
|
|
99
95
|
}
|
|
100
96
|
const assumedUserHeader = ensureArray(headers[this.config.overrides?.assumedUserHeaderName || AuthHeaderName.AssumedUser])[0];
|
|
101
97
|
if (!assumedUserHeader) {
|
|
102
98
|
return undefined;
|
|
103
99
|
}
|
|
104
|
-
const parsedAssumedUserData = await this.config.assumeUser.
|
|
100
|
+
const parsedAssumedUserData = await this.config.assumeUser.parseAssumedUserHeaderValue(assumedUserHeader);
|
|
105
101
|
if (!parsedAssumedUserData || !parsedAssumedUserData.userId) {
|
|
106
102
|
return undefined;
|
|
107
103
|
}
|
|
108
104
|
const assumedUser = await this.getDatabaseUser({
|
|
109
105
|
isSignUpCookie: false,
|
|
110
106
|
userId: parsedAssumedUserData.userId,
|
|
111
|
-
|
|
107
|
+
assumingUser: parsedAssumedUserData.assumedUserParams,
|
|
112
108
|
});
|
|
113
109
|
return assumedUser;
|
|
114
110
|
}
|
|
@@ -120,7 +116,7 @@ export class BackendAuthClient {
|
|
|
120
116
|
}
|
|
121
117
|
const user = await this.getDatabaseUser({
|
|
122
118
|
userId: userIdResult.userId,
|
|
123
|
-
|
|
119
|
+
assumingUser: undefined,
|
|
124
120
|
isSignUpCookie: !!isSignUpCookie,
|
|
125
121
|
});
|
|
126
122
|
if (!user) {
|
|
@@ -128,25 +124,16 @@ export class BackendAuthClient {
|
|
|
128
124
|
}
|
|
129
125
|
const assumedUser = await this.getAssumedUser({
|
|
130
126
|
headers: requestHeaders,
|
|
131
|
-
|
|
127
|
+
user,
|
|
132
128
|
});
|
|
133
129
|
const cookieRefreshHeaders = (await this.createCookieRefreshHeaders({
|
|
134
130
|
userIdResult,
|
|
135
131
|
})) || {};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
return {
|
|
145
|
-
user,
|
|
146
|
-
isAssumed: false,
|
|
147
|
-
responseHeaders: cookieRefreshHeaders,
|
|
148
|
-
};
|
|
149
|
-
}
|
|
132
|
+
return {
|
|
133
|
+
user: assumedUser || user,
|
|
134
|
+
isAssumed: !!assumedUser,
|
|
135
|
+
responseHeaders: cookieRefreshHeaders,
|
|
136
|
+
};
|
|
150
137
|
}
|
|
151
138
|
/**
|
|
152
139
|
* Get all the JWT params used when creating the auth cookie, in case you need them for
|
|
@@ -216,7 +203,7 @@ export class BackendAuthClient {
|
|
|
216
203
|
const user = await this.getDatabaseUser({
|
|
217
204
|
isSignUpCookie: false,
|
|
218
205
|
userId: userIdResult.userId,
|
|
219
|
-
|
|
206
|
+
assumingUser: undefined,
|
|
220
207
|
});
|
|
221
208
|
if (!user) {
|
|
222
209
|
return undefined;
|
package/package.json
CHANGED
|
@@ -49,8 +49,8 @@ export type GetUserResult<DatabaseUser extends AnyObject> = {
|
|
|
49
49
|
export type BackendAuthClientConfig<
|
|
50
50
|
DatabaseUser extends AnyObject,
|
|
51
51
|
UserId extends string | number,
|
|
52
|
-
CsrfHeaderName extends string = AuthHeaderName.CsrfToken,
|
|
53
52
|
AssumedUserParams extends JsonCompatibleObject = EmptyObject,
|
|
53
|
+
CsrfHeaderName extends string = AuthHeaderName.CsrfToken,
|
|
54
54
|
> = Readonly<
|
|
55
55
|
{
|
|
56
56
|
/** The origin of your backend that is offering auth cookies. */
|
|
@@ -65,7 +65,7 @@ export type BackendAuthClientConfig<
|
|
|
65
65
|
* If this is set, we're attempting to load a database user for the purpose of assuming
|
|
66
66
|
* their user identity. Otherwise, this is `undefined`.
|
|
67
67
|
*/
|
|
68
|
-
|
|
68
|
+
assumingUser: AssumedUserParams | undefined;
|
|
69
69
|
}) => MaybePromise<DatabaseUser | undefined | null>;
|
|
70
70
|
/**
|
|
71
71
|
* Get JWT keys produced by {@link generateNewJwtKeys}. Make sure that each time this is
|
|
@@ -88,11 +88,11 @@ export type BackendAuthClientConfig<
|
|
|
88
88
|
*/
|
|
89
89
|
assumeUser: {
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
91
|
+
* Parse the assumed user header value.
|
|
92
92
|
*
|
|
93
93
|
* @see {@link AuthHeaderName}
|
|
94
94
|
*/
|
|
95
|
-
|
|
95
|
+
parseAssumedUserHeaderValue: (
|
|
96
96
|
/**
|
|
97
97
|
* The assumed user header value.
|
|
98
98
|
*
|
|
@@ -107,13 +107,12 @@ export type BackendAuthClientConfig<
|
|
|
107
107
|
| undefined
|
|
108
108
|
>;
|
|
109
109
|
/**
|
|
110
|
-
* Return `true` to allow the current user
|
|
111
|
-
*
|
|
112
|
-
* admin users.
|
|
110
|
+
* Return `true` to allow the current/original user to assume identities of other users.
|
|
111
|
+
* Return `false` to block it. It is recommended to only return `true` for admin users.
|
|
113
112
|
*
|
|
114
113
|
* @see {@link AuthHeaderName}
|
|
115
114
|
*/
|
|
116
|
-
canAssumeUser: (
|
|
115
|
+
canAssumeUser: (originalUser: DatabaseUser) => MaybePromise<boolean>;
|
|
117
116
|
};
|
|
118
117
|
/**
|
|
119
118
|
* This determines how long a cookie will be valid until it needs to be refreshed.
|
|
@@ -149,8 +148,8 @@ const defaultSessionIdleTimeout: Readonly<AnyDuration> = {
|
|
|
149
148
|
export class BackendAuthClient<
|
|
150
149
|
DatabaseUser extends AnyObject,
|
|
151
150
|
UserId extends string | number,
|
|
152
|
-
CsrfHeaderName extends string = AuthHeaderName.CsrfToken,
|
|
153
151
|
AssumedUserParams extends AnyObject = EmptyObject,
|
|
152
|
+
CsrfHeaderName extends string = AuthHeaderName.CsrfToken,
|
|
154
153
|
> {
|
|
155
154
|
protected cachedParsedJwtKeys: Record<string, Readonly<JwtKeys>> = {};
|
|
156
155
|
|
|
@@ -158,8 +157,8 @@ export class BackendAuthClient<
|
|
|
158
157
|
protected readonly config: BackendAuthClientConfig<
|
|
159
158
|
DatabaseUser,
|
|
160
159
|
UserId,
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
AssumedUserParams,
|
|
161
|
+
CsrfHeaderName
|
|
163
162
|
>,
|
|
164
163
|
) {}
|
|
165
164
|
|
|
@@ -188,10 +187,10 @@ export class BackendAuthClient<
|
|
|
188
187
|
protected async getDatabaseUser({
|
|
189
188
|
isSignUpCookie,
|
|
190
189
|
userId,
|
|
191
|
-
|
|
190
|
+
assumingUser,
|
|
192
191
|
}: {
|
|
193
192
|
userId: UserId | undefined;
|
|
194
|
-
|
|
193
|
+
assumingUser: AssumedUserParams | undefined;
|
|
195
194
|
isSignUpCookie: boolean;
|
|
196
195
|
}): Promise<undefined | DatabaseUser> {
|
|
197
196
|
if (!userId) {
|
|
@@ -199,7 +198,7 @@ export class BackendAuthClient<
|
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
const authenticatedUser = await this.config.getUserFromDatabase({
|
|
202
|
-
|
|
201
|
+
assumingUser,
|
|
203
202
|
userId,
|
|
204
203
|
isSignUpCookie,
|
|
205
204
|
});
|
|
@@ -268,18 +267,12 @@ export class BackendAuthClient<
|
|
|
268
267
|
/** Reads the user's assumed user headers and, if configured, gets the assumed user. */
|
|
269
268
|
protected async getAssumedUser({
|
|
270
269
|
headers,
|
|
271
|
-
|
|
270
|
+
user,
|
|
272
271
|
}: {
|
|
273
|
-
|
|
272
|
+
user: DatabaseUser;
|
|
274
273
|
headers: IncomingHttpHeaders;
|
|
275
274
|
}): Promise<DatabaseUser | undefined> {
|
|
276
|
-
if (
|
|
277
|
-
!originalUserId ||
|
|
278
|
-
!this.config.assumeUser ||
|
|
279
|
-
!(await this.config.assumeUser.canAssumeUser({
|
|
280
|
-
userId: originalUserId,
|
|
281
|
-
}))
|
|
282
|
-
) {
|
|
275
|
+
if (!this.config.assumeUser || !(await this.config.assumeUser.canAssumeUser(user))) {
|
|
283
276
|
return undefined;
|
|
284
277
|
}
|
|
285
278
|
|
|
@@ -292,7 +285,7 @@ export class BackendAuthClient<
|
|
|
292
285
|
}
|
|
293
286
|
|
|
294
287
|
const parsedAssumedUserData =
|
|
295
|
-
await this.config.assumeUser.
|
|
288
|
+
await this.config.assumeUser.parseAssumedUserHeaderValue(assumedUserHeader);
|
|
296
289
|
|
|
297
290
|
if (!parsedAssumedUserData || !parsedAssumedUserData.userId) {
|
|
298
291
|
return undefined;
|
|
@@ -301,7 +294,7 @@ export class BackendAuthClient<
|
|
|
301
294
|
const assumedUser = await this.getDatabaseUser({
|
|
302
295
|
isSignUpCookie: false,
|
|
303
296
|
userId: parsedAssumedUserData.userId,
|
|
304
|
-
|
|
297
|
+
assumingUser: parsedAssumedUserData.assumedUserParams,
|
|
305
298
|
});
|
|
306
299
|
|
|
307
300
|
return assumedUser;
|
|
@@ -327,7 +320,7 @@ export class BackendAuthClient<
|
|
|
327
320
|
|
|
328
321
|
const user = await this.getDatabaseUser({
|
|
329
322
|
userId: userIdResult.userId,
|
|
330
|
-
|
|
323
|
+
assumingUser: undefined,
|
|
331
324
|
isSignUpCookie: !!isSignUpCookie,
|
|
332
325
|
});
|
|
333
326
|
|
|
@@ -337,7 +330,7 @@ export class BackendAuthClient<
|
|
|
337
330
|
|
|
338
331
|
const assumedUser = await this.getAssumedUser({
|
|
339
332
|
headers: requestHeaders,
|
|
340
|
-
|
|
333
|
+
user,
|
|
341
334
|
});
|
|
342
335
|
|
|
343
336
|
const cookieRefreshHeaders =
|
|
@@ -345,19 +338,11 @@ export class BackendAuthClient<
|
|
|
345
338
|
userIdResult,
|
|
346
339
|
})) || {};
|
|
347
340
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
};
|
|
354
|
-
} else {
|
|
355
|
-
return {
|
|
356
|
-
user,
|
|
357
|
-
isAssumed: false,
|
|
358
|
-
responseHeaders: cookieRefreshHeaders,
|
|
359
|
-
};
|
|
360
|
-
}
|
|
341
|
+
return {
|
|
342
|
+
user: assumedUser || user,
|
|
343
|
+
isAssumed: !!assumedUser,
|
|
344
|
+
responseHeaders: cookieRefreshHeaders,
|
|
345
|
+
};
|
|
361
346
|
}
|
|
362
347
|
|
|
363
348
|
/**
|
|
@@ -481,7 +466,7 @@ export class BackendAuthClient<
|
|
|
481
466
|
const user = await this.getDatabaseUser({
|
|
482
467
|
isSignUpCookie: false,
|
|
483
468
|
userId: userIdResult.userId,
|
|
484
|
-
|
|
469
|
+
assumingUser: undefined,
|
|
485
470
|
});
|
|
486
471
|
|
|
487
472
|
if (!user) {
|