auth-vir 2.4.1 → 2.5.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.
@@ -58,6 +58,13 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
58
58
  */
59
59
  isDev: boolean;
60
60
  } & PartialWithUndefined<{
61
+ /**
62
+ * Optionally generate a service origin from request headers. The generated origin is used
63
+ * for set-cookie headers.
64
+ */
65
+ generateServiceOrigin(params: {
66
+ requestHeaders: Readonly<IncomingHttpHeaders>;
67
+ }): MaybePromise<undefined | string>;
61
68
  /**
62
69
  * Set this to allow specific users (determined by `canAssumeUser`) to assume the identity
63
70
  * of other users. This should only be used for admins so that they can troubleshoot user
@@ -119,7 +126,7 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
119
126
  protected cachedParsedJwtKeys: Record<string, Readonly<JwtKeys>>;
120
127
  constructor(config: BackendAuthClientConfig<DatabaseUser, UserId, AssumedUserParams, CsrfHeaderName>);
121
128
  /** Get all the parameters used for cookie generation. */
122
- protected getCookieParams({ isSignUpCookie, serviceOrigin, }: {
129
+ protected getCookieParams({ isSignUpCookie, requestHeaders, }: {
123
130
  /**
124
131
  * Set this to `true` when we are setting the initial cookie right after a user signs up.
125
132
  * This allows them to auto-authorize when they verify their email address.
@@ -127,8 +134,7 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
127
134
  * This should only be set to `true` when a new user is signing up.
128
135
  */
129
136
  isSignUpCookie: boolean;
130
- /** Overrides the client's already established `serviceOrigin`. */
131
- serviceOrigin: string | undefined;
137
+ requestHeaders: Readonly<IncomingHttpHeaders> | undefined;
132
138
  }): Promise<Readonly<CookieParams>>;
133
139
  /** Calls the provided `getUserFromDatabase` config. */
134
140
  protected getDatabaseUser({ isSignUpCookie, userId, assumingUser, }: {
@@ -137,8 +143,9 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
137
143
  isSignUpCookie: boolean;
138
144
  }): Promise<undefined | DatabaseUser>;
139
145
  /** Creates a `'cookie-set'` header to refresh the user's session cookie. */
140
- protected createCookieRefreshHeaders({ userIdResult, }: {
146
+ protected createCookieRefreshHeaders({ userIdResult, requestHeaders, }: {
141
147
  userIdResult: Readonly<UserIdResult<UserId>>;
148
+ requestHeaders: IncomingHttpHeaders;
142
149
  }): Promise<OutgoingHttpHeaders | undefined>;
143
150
  /** Reads the user's assumed user headers and, if configured, gets the assumed user. */
144
151
  protected getAssumedUser({ headers, user, }: {
@@ -172,12 +179,10 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
172
179
  'set-cookie': string[];
173
180
  }>;
174
181
  /** Use these headers to log a user in. */
175
- createLoginHeaders({ userId, requestHeaders, isSignUpCookie, serviceOrigin, }: {
182
+ createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }: {
176
183
  userId: UserId;
177
184
  requestHeaders: IncomingHttpHeaders;
178
185
  isSignUpCookie: boolean;
179
- /** Overrides the client's already established `serviceOrigin`. */
180
- serviceOrigin?: string | undefined;
181
186
  }): Promise<OutgoingHttpHeaders>;
182
187
  /** Combines `.getInsecureUser()` and `.getSecureUser()` into one method. */
183
188
  getInsecureOrSecureUser(params: {
@@ -189,6 +194,8 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
189
194
  * with the frontend auth client's `checkUser.performCheck` callback.
190
195
  */
191
196
  allowUserAuthRefresh: boolean;
197
+ /** Overrides the client's already established `serviceOrigin`. */
198
+ serviceOrigin?: string | undefined;
192
199
  }): Promise<RequireOneOrNone<{
193
200
  secureUser: GetUserResult<DatabaseUser>;
194
201
  /**
@@ -24,7 +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, serviceOrigin, }) {
27
+ async getCookieParams({ isSignUpCookie, requestHeaders, }) {
28
+ const serviceOrigin = requestHeaders
29
+ ? await this.config.generateServiceOrigin?.({ requestHeaders })
30
+ : undefined;
28
31
  return {
29
32
  cookieDuration: this.config.userSessionIdleTimeout || defaultSessionIdleTimeout,
30
33
  hostOrigin: serviceOrigin || this.config.serviceOrigin,
@@ -49,7 +52,7 @@ export class BackendAuthClient {
49
52
  return authenticatedUser;
50
53
  }
51
54
  /** Creates a `'cookie-set'` header to refresh the user's session cookie. */
52
- async createCookieRefreshHeaders({ userIdResult, }) {
55
+ async createCookieRefreshHeaders({ userIdResult, requestHeaders, }) {
53
56
  const now = getNowInUtcTimezone();
54
57
  /** Double check that the JWT hasn't already expired. */
55
58
  const isExpiredAlready = isDateAfter({
@@ -80,7 +83,7 @@ export class BackendAuthClient {
80
83
  });
81
84
  if (isRefreshReady) {
82
85
  return this.createLoginHeaders({
83
- requestHeaders: {},
86
+ requestHeaders,
84
87
  userId: userIdResult.userId,
85
88
  isSignUpCookie: userIdResult.cookieName === AuthCookieName.SignUp,
86
89
  });
@@ -129,6 +132,7 @@ export class BackendAuthClient {
129
132
  });
130
133
  const cookieRefreshHeaders = (await this.createCookieRefreshHeaders({
131
134
  userIdResult,
135
+ requestHeaders,
132
136
  })) || {};
133
137
  return {
134
138
  user: assumedUser || user,
@@ -160,13 +164,13 @@ export class BackendAuthClient {
160
164
  const signUpCookieHeaders = params.allCookies || params.isSignUpCookie
161
165
  ? generateLogoutHeaders(await this.getCookieParams({
162
166
  isSignUpCookie: true,
163
- serviceOrigin: params.serviceOrigin,
167
+ requestHeaders: undefined,
164
168
  }), this.config.overrides)
165
169
  : undefined;
166
170
  const authCookieHeaders = params.allCookies || !params.isSignUpCookie
167
171
  ? generateLogoutHeaders(await this.getCookieParams({
168
172
  isSignUpCookie: false,
169
- serviceOrigin: params.serviceOrigin,
173
+ requestHeaders: undefined,
170
174
  }), this.config.overrides)
171
175
  : undefined;
172
176
  const setCookieHeader = {
@@ -182,18 +186,18 @@ export class BackendAuthClient {
182
186
  };
183
187
  }
184
188
  /** Use these headers to log a user in. */
185
- async createLoginHeaders({ userId, requestHeaders, isSignUpCookie, serviceOrigin, }) {
189
+ async createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }) {
186
190
  const oppositeCookieName = isSignUpCookie ? AuthCookieName.Auth : AuthCookieName.SignUp;
187
191
  const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
188
192
  const discardOppositeCookieHeaders = hasExistingOppositeCookie
189
193
  ? generateLogoutHeaders(await this.getCookieParams({
190
194
  isSignUpCookie: !isSignUpCookie,
191
- serviceOrigin,
195
+ requestHeaders,
192
196
  }), this.config.overrides)
193
197
  : undefined;
194
198
  const newCookieHeaders = await generateSuccessfulLoginHeaders(userId, await this.getCookieParams({
195
199
  isSignUpCookie,
196
- serviceOrigin,
200
+ requestHeaders,
197
201
  }), this.config.overrides);
198
202
  return {
199
203
  ...newCookieHeaders,
@@ -237,6 +241,7 @@ export class BackendAuthClient {
237
241
  const refreshHeaders = allowUserAuthRefresh &&
238
242
  (await this.createCookieRefreshHeaders({
239
243
  userIdResult,
244
+ requestHeaders,
240
245
  }));
241
246
  return {
242
247
  user,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-vir",
3
- "version": "2.4.1",
3
+ "version": "2.5.0",
4
4
  "description": "Auth made easy and secure via JWT cookies, CSRF tokens, and password hashing helpers.",
5
5
  "keywords": [
6
6
  "auth",
@@ -78,6 +78,13 @@ export type BackendAuthClientConfig<
78
78
  */
79
79
  isDev: boolean;
80
80
  } & PartialWithUndefined<{
81
+ /**
82
+ * Optionally generate a service origin from request headers. The generated origin is used
83
+ * for set-cookie headers.
84
+ */
85
+ generateServiceOrigin(params: {
86
+ requestHeaders: Readonly<IncomingHttpHeaders>;
87
+ }): MaybePromise<undefined | string>;
81
88
  /**
82
89
  * Set this to allow specific users (determined by `canAssumeUser`) to assume the identity
83
90
  * of other users. This should only be used for admins so that they can troubleshoot user
@@ -168,7 +175,7 @@ export class BackendAuthClient<
168
175
  /** Get all the parameters used for cookie generation. */
169
176
  protected async getCookieParams({
170
177
  isSignUpCookie,
171
- serviceOrigin,
178
+ requestHeaders,
172
179
  }: {
173
180
  /**
174
181
  * Set this to `true` when we are setting the initial cookie right after a user signs up.
@@ -177,9 +184,12 @@ export class BackendAuthClient<
177
184
  * This should only be set to `true` when a new user is signing up.
178
185
  */
179
186
  isSignUpCookie: boolean;
180
- /** Overrides the client's already established `serviceOrigin`. */
181
- serviceOrigin: string | undefined;
187
+ requestHeaders: Readonly<IncomingHttpHeaders> | undefined;
182
188
  }): Promise<Readonly<CookieParams>> {
189
+ const serviceOrigin = requestHeaders
190
+ ? await this.config.generateServiceOrigin?.({requestHeaders})
191
+ : undefined;
192
+
183
193
  return {
184
194
  cookieDuration: this.config.userSessionIdleTimeout || defaultSessionIdleTimeout,
185
195
  hostOrigin: serviceOrigin || this.config.serviceOrigin,
@@ -219,8 +229,10 @@ export class BackendAuthClient<
219
229
  /** Creates a `'cookie-set'` header to refresh the user's session cookie. */
220
230
  protected async createCookieRefreshHeaders({
221
231
  userIdResult,
232
+ requestHeaders,
222
233
  }: {
223
234
  userIdResult: Readonly<UserIdResult<UserId>>;
235
+ requestHeaders: IncomingHttpHeaders;
224
236
  }): Promise<OutgoingHttpHeaders | undefined> {
225
237
  const now = getNowInUtcTimezone();
226
238
 
@@ -259,7 +271,7 @@ export class BackendAuthClient<
259
271
 
260
272
  if (isRefreshReady) {
261
273
  return this.createLoginHeaders({
262
- requestHeaders: {},
274
+ requestHeaders,
263
275
  userId: userIdResult.userId,
264
276
  isSignUpCookie: userIdResult.cookieName === AuthCookieName.SignUp,
265
277
  });
@@ -347,6 +359,7 @@ export class BackendAuthClient<
347
359
  const cookieRefreshHeaders =
348
360
  (await this.createCookieRefreshHeaders({
349
361
  userIdResult,
362
+ requestHeaders,
350
363
  })) || {};
351
364
 
352
365
  return {
@@ -400,7 +413,7 @@ export class BackendAuthClient<
400
413
  ? (generateLogoutHeaders(
401
414
  await this.getCookieParams({
402
415
  isSignUpCookie: true,
403
- serviceOrigin: params.serviceOrigin,
416
+ requestHeaders: undefined,
404
417
  }),
405
418
  this.config.overrides,
406
419
  ) satisfies Record<CsrfHeaderName, string>)
@@ -410,7 +423,7 @@ export class BackendAuthClient<
410
423
  ? (generateLogoutHeaders(
411
424
  await this.getCookieParams({
412
425
  isSignUpCookie: false,
413
- serviceOrigin: params.serviceOrigin,
426
+ requestHeaders: undefined,
414
427
  }),
415
428
  this.config.overrides,
416
429
  ) satisfies Record<CsrfHeaderName, string>)
@@ -440,13 +453,10 @@ export class BackendAuthClient<
440
453
  userId,
441
454
  requestHeaders,
442
455
  isSignUpCookie,
443
- serviceOrigin,
444
456
  }: {
445
457
  userId: UserId;
446
458
  requestHeaders: IncomingHttpHeaders;
447
459
  isSignUpCookie: boolean;
448
- /** Overrides the client's already established `serviceOrigin`. */
449
- serviceOrigin?: string | undefined;
450
460
  }): Promise<OutgoingHttpHeaders> {
451
461
  const oppositeCookieName = isSignUpCookie ? AuthCookieName.Auth : AuthCookieName.SignUp;
452
462
  const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
@@ -455,7 +465,7 @@ export class BackendAuthClient<
455
465
  ? generateLogoutHeaders(
456
466
  await this.getCookieParams({
457
467
  isSignUpCookie: !isSignUpCookie,
458
- serviceOrigin,
468
+ requestHeaders,
459
469
  }),
460
470
  this.config.overrides,
461
471
  )
@@ -465,7 +475,7 @@ export class BackendAuthClient<
465
475
  userId,
466
476
  await this.getCookieParams({
467
477
  isSignUpCookie,
468
- serviceOrigin,
478
+ requestHeaders,
469
479
  }),
470
480
  this.config.overrides,
471
481
  );
@@ -494,6 +504,8 @@ export class BackendAuthClient<
494
504
  * with the frontend auth client's `checkUser.performCheck` callback.
495
505
  */
496
506
  allowUserAuthRefresh: boolean;
507
+ /** Overrides the client's already established `serviceOrigin`. */
508
+ serviceOrigin?: string | undefined;
497
509
  }): Promise<
498
510
  RequireOneOrNone<{
499
511
  secureUser: GetUserResult<DatabaseUser>;
@@ -560,6 +572,7 @@ export class BackendAuthClient<
560
572
  allowUserAuthRefresh &&
561
573
  (await this.createCookieRefreshHeaders({
562
574
  userIdResult,
575
+ requestHeaders,
563
576
  }));
564
577
 
565
578
  return {