auth-vir 2.3.8 → 2.4.0

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.
@@ -119,14 +119,16 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
119
119
  protected cachedParsedJwtKeys: Record<string, Readonly<JwtKeys>>;
120
120
  constructor(config: BackendAuthClientConfig<DatabaseUser, UserId, AssumedUserParams, CsrfHeaderName>);
121
121
  /** Get all the parameters used for cookie generation. */
122
- protected getCookieParams({ isSignUpCookie, }: {
122
+ protected getCookieParams({ isSignUpCookie, serviceOrigin, }: {
123
123
  /**
124
124
  * Set this to `true` when we are setting the initial cookie right after a user signs up.
125
125
  * This allows them to auto-authorize when they verify their email address.
126
126
  *
127
127
  * This should only be set to `true` when a new user is signing up.
128
128
  */
129
- isSignUpCookie?: boolean | undefined;
129
+ isSignUpCookie: boolean;
130
+ /** Overrides the client's already established `serviceOrigin`. */
131
+ serviceOrigin: string | undefined;
130
132
  }): Promise<Readonly<CookieParams>>;
131
133
  /** Calls the provided `getUserFromDatabase` config. */
132
134
  protected getDatabaseUser({ isSignUpCookie, userId, assumingUser, }: {
@@ -144,9 +146,15 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
144
146
  headers: IncomingHttpHeaders;
145
147
  }): Promise<DatabaseUser | undefined>;
146
148
  /** Securely extract a user from their request headers. */
147
- getSecureUser({ requestHeaders, isSignUpCookie, }: {
149
+ getSecureUser({ requestHeaders, isSignUpCookie, allowUserAuthRefresh, }: {
148
150
  requestHeaders: IncomingHttpHeaders;
149
- isSignUpCookie?: boolean | undefined;
151
+ isSignUpCookie: boolean;
152
+ /**
153
+ * If true, this method will generate headers to refresh the user's auth session. This
154
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
155
+ * with the frontend auth client's `checkUser.performCheck` callback.
156
+ */
157
+ allowUserAuthRefresh: boolean;
150
158
  }): Promise<GetUserResult<DatabaseUser> | undefined>;
151
159
  /**
152
160
  * Get all the JWT params used when creating the auth cookie, in case you need them for
@@ -157,19 +165,29 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
157
165
  createLogoutHeaders(params: RequireExactlyOne<{
158
166
  allCookies: true;
159
167
  isSignUpCookie: boolean;
168
+ /** Overrides the client's already established `serviceOrigin`. */
169
+ serviceOrigin?: string | undefined;
160
170
  }>): Promise<Partial<Record<CsrfHeaderName, string>> & {
161
171
  'set-cookie': string[];
162
172
  }>;
163
173
  /** Use these headers to log a user in. */
164
- createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }: {
174
+ createLoginHeaders({ userId, requestHeaders, isSignUpCookie, serviceOrigin, }: {
165
175
  userId: UserId;
166
176
  requestHeaders: IncomingHttpHeaders;
167
177
  isSignUpCookie: boolean;
178
+ /** Overrides the client's already established `serviceOrigin`. */
179
+ serviceOrigin?: string | undefined;
168
180
  }): Promise<OutgoingHttpHeaders>;
169
181
  /** Combines `.getInsecureUser()` and `.getSecureUser()` into one method. */
170
182
  getInsecureOrSecureUser(params: {
171
183
  requestHeaders: IncomingHttpHeaders;
172
- isSignUpCookie?: boolean | undefined;
184
+ isSignUpCookie: boolean;
185
+ /**
186
+ * If true, this method will generate headers to refresh the user's auth session. This
187
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
188
+ * with the frontend auth client's `checkUser.performCheck` callback.
189
+ */
190
+ allowUserAuthRefresh: boolean;
173
191
  }): Promise<RequireOneOrNone<{
174
192
  secureUser: GetUserResult<DatabaseUser>;
175
193
  /**
@@ -185,7 +203,13 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
185
203
  * where JavaScript cannot be used to attach the CSRF token header to the request (like when
186
204
  * opening a PDF file). Use `.getSecureUser()` instead, whenever possible.
187
205
  */
188
- getInsecureUser({ requestHeaders, }: {
206
+ getInsecureUser({ requestHeaders, allowUserAuthRefresh, }: {
189
207
  requestHeaders: IncomingHttpHeaders;
208
+ /**
209
+ * If true, this method will generate headers to refresh the user's auth session. This
210
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
211
+ * with the frontend auth client's `checkUser.performCheck` callback.
212
+ */
213
+ allowUserAuthRefresh: boolean;
190
214
  }): Promise<GetUserResult<DatabaseUser> | undefined>;
191
215
  }
@@ -24,10 +24,10 @@ export class BackendAuthClient {
24
24
  this.config = config;
25
25
  }
26
26
  /** Get all the parameters used for cookie generation. */
27
- async getCookieParams({ isSignUpCookie, }) {
27
+ async getCookieParams({ isSignUpCookie, serviceOrigin, }) {
28
28
  return {
29
29
  cookieDuration: this.config.userSessionIdleTimeout || defaultSessionIdleTimeout,
30
- hostOrigin: this.config.serviceOrigin,
30
+ hostOrigin: serviceOrigin || this.config.serviceOrigin,
31
31
  jwtParams: await this.getJwtParams(),
32
32
  isDev: this.config.isDev,
33
33
  cookieName: isSignUpCookie ? AuthCookieName.SignUp : AuthCookieName.Auth,
@@ -110,7 +110,7 @@ export class BackendAuthClient {
110
110
  return assumedUser;
111
111
  }
112
112
  /** Securely extract a user from their request headers. */
113
- async getSecureUser({ requestHeaders, isSignUpCookie, }) {
113
+ async getSecureUser({ requestHeaders, isSignUpCookie, allowUserAuthRefresh, }) {
114
114
  const userIdResult = await extractUserIdFromRequestHeaders(requestHeaders, await this.getJwtParams(), isSignUpCookie ? AuthCookieName.SignUp : AuthCookieName.Auth, this.config.overrides);
115
115
  if (!userIdResult) {
116
116
  return undefined;
@@ -118,7 +118,7 @@ export class BackendAuthClient {
118
118
  const user = await this.getDatabaseUser({
119
119
  userId: userIdResult.userId,
120
120
  assumingUser: undefined,
121
- isSignUpCookie: !!isSignUpCookie,
121
+ isSignUpCookie,
122
122
  });
123
123
  if (!user) {
124
124
  return undefined;
@@ -133,7 +133,7 @@ export class BackendAuthClient {
133
133
  return {
134
134
  user: assumedUser || user,
135
135
  isAssumed: !!assumedUser,
136
- responseHeaders: cookieRefreshHeaders,
136
+ responseHeaders: allowUserAuthRefresh ? cookieRefreshHeaders : {},
137
137
  };
138
138
  }
139
139
  /**
@@ -160,11 +160,13 @@ export class BackendAuthClient {
160
160
  const signUpCookieHeaders = params.allCookies || params.isSignUpCookie
161
161
  ? generateLogoutHeaders(await this.getCookieParams({
162
162
  isSignUpCookie: true,
163
+ serviceOrigin: params.serviceOrigin,
163
164
  }), this.config.overrides)
164
165
  : undefined;
165
166
  const authCookieHeaders = params.allCookies || !params.isSignUpCookie
166
167
  ? generateLogoutHeaders(await this.getCookieParams({
167
168
  isSignUpCookie: false,
169
+ serviceOrigin: params.serviceOrigin,
168
170
  }), this.config.overrides)
169
171
  : undefined;
170
172
  const setCookieHeader = {
@@ -180,16 +182,18 @@ export class BackendAuthClient {
180
182
  };
181
183
  }
182
184
  /** Use these headers to log a user in. */
183
- async createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }) {
185
+ async createLoginHeaders({ userId, requestHeaders, isSignUpCookie, serviceOrigin, }) {
184
186
  const oppositeCookieName = isSignUpCookie ? AuthCookieName.Auth : AuthCookieName.SignUp;
185
187
  const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
186
188
  const discardOppositeCookieHeaders = hasExistingOppositeCookie
187
189
  ? generateLogoutHeaders(await this.getCookieParams({
188
190
  isSignUpCookie: !isSignUpCookie,
191
+ serviceOrigin,
189
192
  }), this.config.overrides)
190
193
  : undefined;
191
194
  const newCookieHeaders = await generateSuccessfulLoginHeaders(userId, await this.getCookieParams({
192
195
  isSignUpCookie,
196
+ serviceOrigin,
193
197
  }), this.config.overrides);
194
198
  return {
195
199
  ...newCookieHeaders,
@@ -216,7 +220,7 @@ export class BackendAuthClient {
216
220
  * where JavaScript cannot be used to attach the CSRF token header to the request (like when
217
221
  * opening a PDF file). Use `.getSecureUser()` instead, whenever possible.
218
222
  */
219
- async getInsecureUser({ requestHeaders, }) {
223
+ async getInsecureUser({ requestHeaders, allowUserAuthRefresh, }) {
220
224
  // eslint-disable-next-line @typescript-eslint/no-deprecated
221
225
  const userIdResult = await insecureExtractUserIdFromCookieAlone(requestHeaders, await this.getJwtParams(), AuthCookieName.Auth);
222
226
  if (!userIdResult) {
@@ -230,12 +234,14 @@ export class BackendAuthClient {
230
234
  if (!user) {
231
235
  return undefined;
232
236
  }
237
+ const refreshHeaders = allowUserAuthRefresh &&
238
+ (await this.createCookieRefreshHeaders({
239
+ userIdResult,
240
+ }));
233
241
  return {
234
242
  user,
235
243
  isAssumed: false,
236
- responseHeaders: (await this.createCookieRefreshHeaders({
237
- userIdResult,
238
- })) || {},
244
+ responseHeaders: refreshHeaders || {},
239
245
  };
240
246
  }
241
247
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-vir",
3
- "version": "2.3.8",
3
+ "version": "2.4.0",
4
4
  "description": "Auth made easy and secure via JWT cookies, CSRF tokens, and password hashing helpers.",
5
5
  "keywords": [
6
6
  "auth",
@@ -168,6 +168,7 @@ export class BackendAuthClient<
168
168
  /** Get all the parameters used for cookie generation. */
169
169
  protected async getCookieParams({
170
170
  isSignUpCookie,
171
+ serviceOrigin,
171
172
  }: {
172
173
  /**
173
174
  * Set this to `true` when we are setting the initial cookie right after a user signs up.
@@ -175,11 +176,13 @@ export class BackendAuthClient<
175
176
  *
176
177
  * This should only be set to `true` when a new user is signing up.
177
178
  */
178
- isSignUpCookie?: boolean | undefined;
179
+ isSignUpCookie: boolean;
180
+ /** Overrides the client's already established `serviceOrigin`. */
181
+ serviceOrigin: string | undefined;
179
182
  }): Promise<Readonly<CookieParams>> {
180
183
  return {
181
184
  cookieDuration: this.config.userSessionIdleTimeout || defaultSessionIdleTimeout,
182
- hostOrigin: this.config.serviceOrigin,
185
+ hostOrigin: serviceOrigin || this.config.serviceOrigin,
183
186
  jwtParams: await this.getJwtParams(),
184
187
  isDev: this.config.isDev,
185
188
  cookieName: isSignUpCookie ? AuthCookieName.SignUp : AuthCookieName.Auth,
@@ -305,9 +308,16 @@ export class BackendAuthClient<
305
308
  public async getSecureUser({
306
309
  requestHeaders,
307
310
  isSignUpCookie,
311
+ allowUserAuthRefresh,
308
312
  }: {
309
313
  requestHeaders: IncomingHttpHeaders;
310
- isSignUpCookie?: boolean | undefined;
314
+ isSignUpCookie: boolean;
315
+ /**
316
+ * If true, this method will generate headers to refresh the user's auth session. This
317
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
318
+ * with the frontend auth client's `checkUser.performCheck` callback.
319
+ */
320
+ allowUserAuthRefresh: boolean;
311
321
  }): Promise<GetUserResult<DatabaseUser> | undefined> {
312
322
  const userIdResult = await extractUserIdFromRequestHeaders<UserId>(
313
323
  requestHeaders,
@@ -322,7 +332,7 @@ export class BackendAuthClient<
322
332
  const user = await this.getDatabaseUser({
323
333
  userId: userIdResult.userId,
324
334
  assumingUser: undefined,
325
- isSignUpCookie: !!isSignUpCookie,
335
+ isSignUpCookie,
326
336
  });
327
337
 
328
338
  if (!user) {
@@ -342,7 +352,7 @@ export class BackendAuthClient<
342
352
  return {
343
353
  user: assumedUser || user,
344
354
  isAssumed: !!assumedUser,
345
- responseHeaders: cookieRefreshHeaders,
355
+ responseHeaders: allowUserAuthRefresh ? cookieRefreshHeaders : {},
346
356
  };
347
357
  }
348
358
 
@@ -374,6 +384,8 @@ export class BackendAuthClient<
374
384
  params: RequireExactlyOne<{
375
385
  allCookies: true;
376
386
  isSignUpCookie: boolean;
387
+ /** Overrides the client's already established `serviceOrigin`. */
388
+ serviceOrigin?: string | undefined;
377
389
  }>,
378
390
  ): Promise<
379
391
  Partial<Record<CsrfHeaderName, string>> & {
@@ -385,6 +397,7 @@ export class BackendAuthClient<
385
397
  ? (generateLogoutHeaders(
386
398
  await this.getCookieParams({
387
399
  isSignUpCookie: true,
400
+ serviceOrigin: params.serviceOrigin,
388
401
  }),
389
402
  this.config.overrides,
390
403
  ) satisfies Record<CsrfHeaderName, string>)
@@ -394,6 +407,7 @@ export class BackendAuthClient<
394
407
  ? (generateLogoutHeaders(
395
408
  await this.getCookieParams({
396
409
  isSignUpCookie: false,
410
+ serviceOrigin: params.serviceOrigin,
397
411
  }),
398
412
  this.config.overrides,
399
413
  ) satisfies Record<CsrfHeaderName, string>)
@@ -423,10 +437,13 @@ export class BackendAuthClient<
423
437
  userId,
424
438
  requestHeaders,
425
439
  isSignUpCookie,
440
+ serviceOrigin,
426
441
  }: {
427
442
  userId: UserId;
428
443
  requestHeaders: IncomingHttpHeaders;
429
444
  isSignUpCookie: boolean;
445
+ /** Overrides the client's already established `serviceOrigin`. */
446
+ serviceOrigin?: string | undefined;
430
447
  }): Promise<OutgoingHttpHeaders> {
431
448
  const oppositeCookieName = isSignUpCookie ? AuthCookieName.Auth : AuthCookieName.SignUp;
432
449
  const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
@@ -435,6 +452,7 @@ export class BackendAuthClient<
435
452
  ? generateLogoutHeaders(
436
453
  await this.getCookieParams({
437
454
  isSignUpCookie: !isSignUpCookie,
455
+ serviceOrigin,
438
456
  }),
439
457
  this.config.overrides,
440
458
  )
@@ -444,6 +462,7 @@ export class BackendAuthClient<
444
462
  userId,
445
463
  await this.getCookieParams({
446
464
  isSignUpCookie,
465
+ serviceOrigin,
447
466
  }),
448
467
  this.config.overrides,
449
468
  );
@@ -465,7 +484,13 @@ export class BackendAuthClient<
465
484
  /** Combines `.getInsecureUser()` and `.getSecureUser()` into one method. */
466
485
  public async getInsecureOrSecureUser(params: {
467
486
  requestHeaders: IncomingHttpHeaders;
468
- isSignUpCookie?: boolean | undefined;
487
+ isSignUpCookie: boolean;
488
+ /**
489
+ * If true, this method will generate headers to refresh the user's auth session. This
490
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
491
+ * with the frontend auth client's `checkUser.performCheck` callback.
492
+ */
493
+ allowUserAuthRefresh: boolean;
469
494
  }): Promise<
470
495
  RequireOneOrNone<{
471
496
  secureUser: GetUserResult<DatabaseUser>;
@@ -497,8 +522,15 @@ export class BackendAuthClient<
497
522
  */
498
523
  public async getInsecureUser({
499
524
  requestHeaders,
525
+ allowUserAuthRefresh,
500
526
  }: {
501
527
  requestHeaders: IncomingHttpHeaders;
528
+ /**
529
+ * If true, this method will generate headers to refresh the user's auth session. This
530
+ * should likely only be done with a specific endpoint, like whatever endpoint you trigger
531
+ * with the frontend auth client's `checkUser.performCheck` callback.
532
+ */
533
+ allowUserAuthRefresh: boolean;
502
534
  }): Promise<GetUserResult<DatabaseUser> | undefined> {
503
535
  // eslint-disable-next-line @typescript-eslint/no-deprecated
504
536
  const userIdResult = await insecureExtractUserIdFromCookieAlone<UserId>(
@@ -521,13 +553,16 @@ export class BackendAuthClient<
521
553
  return undefined;
522
554
  }
523
555
 
556
+ const refreshHeaders =
557
+ allowUserAuthRefresh &&
558
+ (await this.createCookieRefreshHeaders({
559
+ userIdResult,
560
+ }));
561
+
524
562
  return {
525
563
  user,
526
564
  isAssumed: false,
527
- responseHeaders:
528
- (await this.createCookieRefreshHeaders({
529
- userIdResult,
530
- })) || {},
565
+ responseHeaders: refreshHeaders || {},
531
566
  };
532
567
  }
533
568
  }