@maestro-js/auth 1.0.0-alpha.24 → 1.0.0-alpha.25
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/index.d.ts +14 -1
- package/dist/index.js +24 -7
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ interface RememberMeTokenRecordType<Id, DeviceContext> {
|
|
|
14
14
|
verifierHash: string;
|
|
15
15
|
expirationDate: Iso.Instant | null;
|
|
16
16
|
rotatedDate: Iso.Instant | null;
|
|
17
|
+
/**
|
|
18
|
+
* When the token chain was first issued (at login). Successor rows produced by `rotateBySelector`
|
|
19
|
+
* must inherit this value rather than resetting it, so it always reflects the original grant time.
|
|
20
|
+
* Used to reject cookies whose chain predates a credential invalidation.
|
|
21
|
+
*/
|
|
22
|
+
createdDate: Iso.Instant;
|
|
17
23
|
}
|
|
18
24
|
interface RememberMeOptionsType<Id, DeviceContext> {
|
|
19
25
|
maxRememberMeSeconds: number;
|
|
@@ -23,7 +29,7 @@ interface RememberMeOptionsType<Id, DeviceContext> {
|
|
|
23
29
|
rotateBySelector(selector: string, token: {
|
|
24
30
|
verifierHash: string;
|
|
25
31
|
selector: string;
|
|
26
|
-
}): Promise<
|
|
32
|
+
}): Promise<boolean>;
|
|
27
33
|
revokeBySelector(selector: string): Promise<void>;
|
|
28
34
|
revokeByAuthenticatableId(id: Id): Promise<void>;
|
|
29
35
|
validateDeviceContext?(creatingDeviceContext: DeviceContext, currentDeviceContext: DeviceContext): Promise<boolean> | boolean;
|
|
@@ -129,6 +135,13 @@ declare namespace Auth {
|
|
|
129
135
|
id: Id | null;
|
|
130
136
|
cookie: string | null;
|
|
131
137
|
}>;
|
|
138
|
+
/**
|
|
139
|
+
* Delete all stored remember-me token rows for an authenticatable. `authenticate` already
|
|
140
|
+
* rejects any chain issued before `credentialsInvalidBefore`, so credential-invalidating
|
|
141
|
+
* flows (e.g. password reset) are secure without this; call it to immediately clean up the
|
|
142
|
+
* rows instead of leaving them to expire. No-op when remember-me is not configured.
|
|
143
|
+
*/
|
|
144
|
+
revokeRememberMeTokens(id: Id): Promise<void>;
|
|
132
145
|
};
|
|
133
146
|
interface AuthServiceConfig<Id, Credentials, DeviceContext> {
|
|
134
147
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ function createRememberMeProvider({
|
|
|
20
20
|
deviceContext: options.deviceContext,
|
|
21
21
|
expirationDate: options.expirationDate,
|
|
22
22
|
rotatedDate: null,
|
|
23
|
+
createdDate: instantFns.now(),
|
|
23
24
|
selector,
|
|
24
25
|
verifierHash
|
|
25
26
|
});
|
|
@@ -49,16 +50,19 @@ function createRememberMeProvider({
|
|
|
49
50
|
if (validateDeviceContext && !await validateDeviceContext(record.deviceContext, deviceContext)) {
|
|
50
51
|
return null;
|
|
51
52
|
}
|
|
52
|
-
return record.authenticatableId;
|
|
53
|
+
return { id: record.authenticatableId, tokenCreatedDate: record.createdDate };
|
|
53
54
|
}
|
|
54
55
|
async function rotate(previousSelector) {
|
|
55
56
|
const selector = crypto.randomBytes(16).toString("base64url");
|
|
56
57
|
const verifier = crypto.randomBytes(32).toString("base64url");
|
|
57
58
|
const verifierHash = await hash.hash(verifier);
|
|
58
|
-
await db.rotateBySelector(previousSelector, {
|
|
59
|
+
const claimed = await db.rotateBySelector(previousSelector, {
|
|
59
60
|
selector,
|
|
60
61
|
verifierHash
|
|
61
62
|
});
|
|
63
|
+
if (!claimed) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
62
66
|
return { selector, verifier };
|
|
63
67
|
}
|
|
64
68
|
async function revoke(token) {
|
|
@@ -180,19 +184,25 @@ function create(config) {
|
|
|
180
184
|
if (!rememberMeToken) {
|
|
181
185
|
return NO_AUTH;
|
|
182
186
|
}
|
|
183
|
-
const
|
|
184
|
-
if (!
|
|
187
|
+
const validated = await rememberMeProvider.validate({ token: rememberMeToken, deviceContext });
|
|
188
|
+
if (!validated) {
|
|
185
189
|
return NO_AUTH;
|
|
186
190
|
}
|
|
187
|
-
const authenticatable = await config.getAuthenticatableById(id);
|
|
191
|
+
const authenticatable = await config.getAuthenticatableById(validated.id);
|
|
188
192
|
if (!authenticatable) {
|
|
189
193
|
return NO_AUTH;
|
|
190
194
|
}
|
|
195
|
+
if (authenticatable.credentialsInvalidBefore && validated.tokenCreatedDate < authenticatable.credentialsInvalidBefore) {
|
|
196
|
+
return NO_AUTH;
|
|
197
|
+
}
|
|
191
198
|
const newRememberMeToken = await rememberMeProvider.rotate(rememberMeToken.selector);
|
|
192
199
|
session.set(ID_SESSION_KEY, authenticatable.id);
|
|
193
200
|
session.set(AUTH_PROVIDER_NAME_SESSION_KEY, config.name);
|
|
194
201
|
session.set(SESSION_CREATED_DATE_KEY, instantFns2.now());
|
|
195
202
|
session.regenerate();
|
|
203
|
+
if (!newRememberMeToken) {
|
|
204
|
+
return { id: authenticatable.id, cookie: null };
|
|
205
|
+
}
|
|
196
206
|
return {
|
|
197
207
|
id: authenticatable.id,
|
|
198
208
|
cookie: getCookie({
|
|
@@ -246,6 +256,11 @@ function create(config) {
|
|
|
246
256
|
session
|
|
247
257
|
});
|
|
248
258
|
}
|
|
259
|
+
async function revokeRememberMeTokens(id) {
|
|
260
|
+
if (config.rememberMeOptions) {
|
|
261
|
+
await rememberMeProvider.revokeAll(id);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
249
264
|
function getCookie({ rememberMeCookieValue }) {
|
|
250
265
|
if (rememberMeCookieValue) {
|
|
251
266
|
return buildSetCookieHeader({
|
|
@@ -268,7 +283,8 @@ function create(config) {
|
|
|
268
283
|
loginById,
|
|
269
284
|
authenticate,
|
|
270
285
|
logout,
|
|
271
|
-
logoutOtherDevices
|
|
286
|
+
logoutOtherDevices,
|
|
287
|
+
revokeRememberMeTokens
|
|
272
288
|
};
|
|
273
289
|
}
|
|
274
290
|
var registry = ServiceRegistry.createRegistry(
|
|
@@ -285,7 +301,8 @@ function provider(key) {
|
|
|
285
301
|
loginById: service.loginById,
|
|
286
302
|
authenticate: service.authenticate,
|
|
287
303
|
logout: service.logout,
|
|
288
|
-
logoutOtherDevices: service.logoutOtherDevices
|
|
304
|
+
logoutOtherDevices: service.logoutOtherDevices,
|
|
305
|
+
revokeRememberMeTokens: service.revokeRememberMeTokens
|
|
289
306
|
};
|
|
290
307
|
}
|
|
291
308
|
var AuthBase = {
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"default": "./dist/index.js"
|
|
8
8
|
}
|
|
9
9
|
},
|
|
10
|
-
"version": "1.0.0-alpha.
|
|
10
|
+
"version": "1.0.0-alpha.25",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"iso-fns2": "npm:iso-fns@2.0.0-alpha.26",
|
|
19
|
-
"@maestro-js/service-registry": "1.0.0-alpha.
|
|
19
|
+
"@maestro-js/service-registry": "1.0.0-alpha.25"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@maestro-js/
|
|
23
|
-
"@maestro-js/hash": "1.0.0-alpha.
|
|
24
|
-
"@maestro-js/
|
|
22
|
+
"@maestro-js/crypt": "1.0.0-alpha.25",
|
|
23
|
+
"@maestro-js/hash": "1.0.0-alpha.25",
|
|
24
|
+
"@maestro-js/session": "1.0.0-alpha.25"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^22.19.11",
|
|
28
|
-
"@maestro-js/session": "1.0.0-alpha.
|
|
29
|
-
"@maestro-js/crypt": "1.0.0-alpha.
|
|
30
|
-
"@maestro-js/hash": "1.0.0-alpha.
|
|
28
|
+
"@maestro-js/session": "1.0.0-alpha.25",
|
|
29
|
+
"@maestro-js/crypt": "1.0.0-alpha.25",
|
|
30
|
+
"@maestro-js/hash": "1.0.0-alpha.25"
|
|
31
31
|
},
|
|
32
32
|
"license": "UNLICENSED",
|
|
33
33
|
"engines": {
|