auth-vir 2.1.0 → 2.2.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.
- package/dist/auth-client/backend-auth.client.d.ts +7 -4
- package/dist/auth-client/backend-auth.client.js +20 -9
- package/dist/auth-client/frontend-auth.client.d.ts +2 -2
- package/dist/auth-client/frontend-auth.client.js +4 -8
- package/package.json +5 -5
- package/src/auth-client/backend-auth.client.ts +43 -22
- package/src/auth-client/frontend-auth.client.ts +15 -15
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type AnyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type RequiredAndNotNull } from '@augment-vir/common';
|
|
2
2
|
import { type AnyDuration } from 'date-vir';
|
|
3
3
|
import { type IncomingHttpHeaders, type OutgoingHttpHeaders } from 'node:http';
|
|
4
|
-
import { type EmptyObject } from 'type-fest';
|
|
4
|
+
import { type EmptyObject, type RequireExactlyOne } from 'type-fest';
|
|
5
5
|
import { type UserIdResult } from '../auth.js';
|
|
6
6
|
import { type CookieParams } from '../cookie.js';
|
|
7
7
|
import { AuthHeaderName } from '../headers.js';
|
|
@@ -154,9 +154,12 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
|
|
|
154
154
|
*/
|
|
155
155
|
getJwtParams(): Promise<Readonly<CreateJwtParams>>;
|
|
156
156
|
/** Use these headers to log out the user. */
|
|
157
|
-
createLogoutHeaders(
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
createLogoutHeaders(params: RequireExactlyOne<{
|
|
158
|
+
allCookies: true;
|
|
159
|
+
isSignUpCookie: boolean;
|
|
160
|
+
}>): Promise<Partial<Record<CsrfHeaderName, string>> & {
|
|
161
|
+
'set-cookie': string[];
|
|
162
|
+
}>;
|
|
160
163
|
/** Use these headers to log a user in. */
|
|
161
164
|
createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }: {
|
|
162
165
|
userId: UserId;
|
|
@@ -155,16 +155,27 @@ export class BackendAuthClient {
|
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
157
|
/** Use these headers to log out the user. */
|
|
158
|
-
async createLogoutHeaders() {
|
|
159
|
-
const signUpCookieHeaders =
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
async createLogoutHeaders(params) {
|
|
159
|
+
const signUpCookieHeaders = params.allCookies || params.isSignUpCookie
|
|
160
|
+
? generateLogoutHeaders(await this.getCookieParams({
|
|
161
|
+
isSignUpCookie: true,
|
|
162
|
+
}), this.config.overrides)
|
|
163
|
+
: undefined;
|
|
164
|
+
const authCookieHeaders = params.allCookies || !params.isSignUpCookie
|
|
165
|
+
? generateLogoutHeaders(await this.getCookieParams({
|
|
166
|
+
isSignUpCookie: false,
|
|
167
|
+
}), this.config.overrides)
|
|
168
|
+
: undefined;
|
|
169
|
+
const setCookieHeader = {
|
|
170
|
+
'set-cookie': mergeHeaderValues(signUpCookieHeaders?.['set-cookie'], authCookieHeaders?.['set-cookie']),
|
|
171
|
+
};
|
|
172
|
+
const csrfTokenHeader = {
|
|
166
173
|
...authCookieHeaders,
|
|
167
|
-
|
|
174
|
+
...signUpCookieHeaders,
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
...csrfTokenHeader,
|
|
178
|
+
...setCookieHeader,
|
|
168
179
|
};
|
|
169
180
|
}
|
|
170
181
|
/** Use these headers to log a user in. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom, type SetOptionalWithUndefined } from '@augment-vir/common';
|
|
1
|
+
import { createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom, type SetOptionalWithUndefined } from '@augment-vir/common';
|
|
2
2
|
import { type AnyDuration } from 'date-vir';
|
|
3
3
|
import { type EmptyObject } from 'type-fest';
|
|
4
4
|
/**
|
|
@@ -45,7 +45,7 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
|
|
|
45
45
|
*/
|
|
46
46
|
export declare class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject = EmptyObject> {
|
|
47
47
|
protected readonly config: FrontendAuthClientConfig;
|
|
48
|
-
protected userCheckInterval: undefined | ReturnType<typeof
|
|
48
|
+
protected userCheckInterval: undefined | ReturnType<typeof createBlockingInterval>;
|
|
49
49
|
constructor(config?: FrontendAuthClientConfig);
|
|
50
50
|
/**
|
|
51
51
|
* Destroys the client and performs all necessary cleanup (like clearing the user check
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { HttpStatus, } from '@augment-vir/common';
|
|
2
|
-
import { convertDuration } from 'date-vir';
|
|
1
|
+
import { createBlockingInterval, HttpStatus, } from '@augment-vir/common';
|
|
3
2
|
import { CsrfTokenFailureReason, extractCsrfTokenHeader, getCurrentCsrfToken, storeCsrfToken, wipeCurrentCsrfToken, } from '../csrf-token.js';
|
|
4
3
|
import { AuthHeaderName } from '../headers.js';
|
|
5
4
|
/**
|
|
@@ -15,17 +14,14 @@ export class FrontendAuthClient {
|
|
|
15
14
|
constructor(config = {}) {
|
|
16
15
|
this.config = config;
|
|
17
16
|
if (config.checkUser) {
|
|
18
|
-
|
|
19
|
-
milliseconds: true,
|
|
20
|
-
}).milliseconds;
|
|
21
|
-
this.userCheckInterval = globalThis.setInterval(async () => {
|
|
17
|
+
this.userCheckInterval = createBlockingInterval(async () => {
|
|
22
18
|
const response = await config.checkUser?.performCheck();
|
|
23
19
|
if (response) {
|
|
24
20
|
await this.verifyResponseAuth({
|
|
25
21
|
status: response.status,
|
|
26
22
|
});
|
|
27
23
|
}
|
|
28
|
-
},
|
|
24
|
+
}, config.checkUser.interval || { minutes: 1 });
|
|
29
25
|
}
|
|
30
26
|
}
|
|
31
27
|
/**
|
|
@@ -33,7 +29,7 @@ export class FrontendAuthClient {
|
|
|
33
29
|
* interval).
|
|
34
30
|
*/
|
|
35
31
|
destroy() {
|
|
36
|
-
|
|
32
|
+
this.userCheckInterval?.clearInterval();
|
|
37
33
|
}
|
|
38
34
|
/** Wraps {@link getCurrentCsrfToken} to automatically handle wiping an invalid CSRF token. */
|
|
39
35
|
async getCurrentCsrfToken() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auth-vir",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Auth made easy and secure via JWT cookies, CSRF tokens, and password hashing helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"test:web": "virmator test web"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@augment-vir/assert": "^31.
|
|
46
|
-
"@augment-vir/common": "^31.
|
|
45
|
+
"@augment-vir/assert": "^31.42.0",
|
|
46
|
+
"@augment-vir/common": "^31.42.0",
|
|
47
47
|
"date-vir": "^8.0.0",
|
|
48
48
|
"hash-wasm": "^4.12.0",
|
|
49
49
|
"jose": "^6.1.0",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"url-vir": "^2.1.6"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@augment-vir/test": "^31.
|
|
55
|
+
"@augment-vir/test": "^31.42.0",
|
|
56
56
|
"@prisma/client": "^6.17.1",
|
|
57
|
-
"@types/node": "^24.
|
|
57
|
+
"@types/node": "^24.9.1",
|
|
58
58
|
"@web/dev-server-esbuild": "^1.0.4",
|
|
59
59
|
"@web/test-runner": "^0.20.2",
|
|
60
60
|
"@web/test-runner-commands": "^0.9.0",
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from '@augment-vir/common';
|
|
9
9
|
import {calculateRelativeDate, getNowInUtcTimezone, isDateAfter, type AnyDuration} from 'date-vir';
|
|
10
10
|
import {type IncomingHttpHeaders, type OutgoingHttpHeaders} from 'node:http';
|
|
11
|
-
import {type EmptyObject} from 'type-fest';
|
|
11
|
+
import {type EmptyObject, type RequireExactlyOne} from 'type-fest';
|
|
12
12
|
import {
|
|
13
13
|
extractUserIdFromRequestHeaders,
|
|
14
14
|
generateLogoutHeaders,
|
|
@@ -369,31 +369,52 @@ export class BackendAuthClient<
|
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
/** Use these headers to log out the user. */
|
|
372
|
-
public async createLogoutHeaders(
|
|
373
|
-
{
|
|
374
|
-
|
|
375
|
-
|
|
372
|
+
public async createLogoutHeaders(
|
|
373
|
+
params: RequireExactlyOne<{
|
|
374
|
+
allCookies: true;
|
|
375
|
+
isSignUpCookie: boolean;
|
|
376
|
+
}>,
|
|
377
|
+
): Promise<
|
|
378
|
+
Partial<Record<CsrfHeaderName, string>> & {
|
|
379
|
+
'set-cookie': string[];
|
|
380
|
+
}
|
|
376
381
|
> {
|
|
377
|
-
const signUpCookieHeaders =
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
382
|
+
const signUpCookieHeaders =
|
|
383
|
+
params.allCookies || params.isSignUpCookie
|
|
384
|
+
? (generateLogoutHeaders(
|
|
385
|
+
await this.getCookieParams({
|
|
386
|
+
isSignUpCookie: true,
|
|
387
|
+
}),
|
|
388
|
+
this.config.overrides,
|
|
389
|
+
) satisfies Record<CsrfHeaderName, string>)
|
|
390
|
+
: undefined;
|
|
391
|
+
const authCookieHeaders =
|
|
392
|
+
params.allCookies || !params.isSignUpCookie
|
|
393
|
+
? (generateLogoutHeaders(
|
|
394
|
+
await this.getCookieParams({
|
|
395
|
+
isSignUpCookie: false,
|
|
396
|
+
}),
|
|
397
|
+
this.config.overrides,
|
|
398
|
+
) satisfies Record<CsrfHeaderName, string>)
|
|
399
|
+
: undefined;
|
|
400
|
+
|
|
401
|
+
const setCookieHeader: {
|
|
402
|
+
'set-cookie': string[];
|
|
403
|
+
} = {
|
|
392
404
|
'set-cookie': mergeHeaderValues(
|
|
393
|
-
signUpCookieHeaders['set-cookie'],
|
|
394
|
-
authCookieHeaders['set-cookie'],
|
|
405
|
+
signUpCookieHeaders?.['set-cookie'],
|
|
406
|
+
authCookieHeaders?.['set-cookie'],
|
|
395
407
|
),
|
|
396
408
|
};
|
|
409
|
+
const csrfTokenHeader = {
|
|
410
|
+
...authCookieHeaders,
|
|
411
|
+
...signUpCookieHeaders,
|
|
412
|
+
} as Record<CsrfHeaderName, string>;
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
...csrfTokenHeader,
|
|
416
|
+
...setCookieHeader,
|
|
417
|
+
};
|
|
397
418
|
}
|
|
398
419
|
|
|
399
420
|
/** Use these headers to log a user in. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createBlockingInterval,
|
|
2
3
|
HttpStatus,
|
|
3
4
|
type JsonCompatibleObject,
|
|
4
5
|
type MaybePromise,
|
|
@@ -6,7 +7,7 @@ import {
|
|
|
6
7
|
type SelectFrom,
|
|
7
8
|
type SetOptionalWithUndefined,
|
|
8
9
|
} from '@augment-vir/common';
|
|
9
|
-
import {
|
|
10
|
+
import {type AnyDuration} from 'date-vir';
|
|
10
11
|
import {type EmptyObject} from 'type-fest';
|
|
11
12
|
import {
|
|
12
13
|
CsrfTokenFailureReason,
|
|
@@ -68,22 +69,21 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
|
|
|
68
69
|
* @category Client
|
|
69
70
|
*/
|
|
70
71
|
export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject = EmptyObject> {
|
|
71
|
-
protected userCheckInterval: undefined | ReturnType<typeof
|
|
72
|
+
protected userCheckInterval: undefined | ReturnType<typeof createBlockingInterval>;
|
|
72
73
|
|
|
73
74
|
constructor(protected readonly config: FrontendAuthClientConfig = {}) {
|
|
74
75
|
if (config.checkUser) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}, intervalDuration);
|
|
76
|
+
this.userCheckInterval = createBlockingInterval(
|
|
77
|
+
async () => {
|
|
78
|
+
const response = await config.checkUser?.performCheck();
|
|
79
|
+
if (response) {
|
|
80
|
+
await this.verifyResponseAuth({
|
|
81
|
+
status: response.status,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
config.checkUser.interval || {minutes: 1},
|
|
86
|
+
);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -92,7 +92,7 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
|
|
|
92
92
|
* interval).
|
|
93
93
|
*/
|
|
94
94
|
public destroy() {
|
|
95
|
-
|
|
95
|
+
this.userCheckInterval?.clearInterval();
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/** Wraps {@link getCurrentCsrfToken} to automatically handle wiping an invalid CSRF token. */
|