@absolutejs/auth 0.75.0 → 0.75.2
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/README.md +13 -0
- package/dist/agents/config.d.ts +5 -1
- package/dist/agents/index.js +47 -11
- package/dist/agents/index.js.map +5 -5
- package/dist/agents/oidcAdapter.d.ts +3 -1
- package/dist/agents/routes.d.ts +2 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +64 -24
- package/dist/index.js.map +8 -8
- package/dist/nativePush.d.ts +14 -14
- package/dist/oidc/dpop.d.ts +6 -2
- package/dist/oidc/index.d.ts +1 -0
- package/dist/oidc/index.js +130 -1
- package/dist/oidc/index.js.map +4 -3
- package/dist/server.js +64 -24
- package/dist/server.js.map +8 -8
- package/package.json +1 -1
package/dist/nativePush.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AuthSessionSource } from './session/types';
|
|
2
2
|
import { type AccessTokenPrincipalConfig, type AuthPrincipal } from './principal';
|
|
3
|
-
export declare const DEFAULT_PUSH_ROUTE: "/auth/push";
|
|
4
|
-
/** @deprecated Use DEFAULT_PUSH_ROUTE. Kept for installed beta clients. */
|
|
5
3
|
export declare const DEFAULT_NATIVE_PUSH_ROUTE: "/auth/mobile/push";
|
|
4
|
+
/** Canonical cross-platform push route. */
|
|
5
|
+
export declare const DEFAULT_PUSH_ROUTE: "/auth/push";
|
|
6
6
|
export type PushPlatform = 'apns' | 'fcm' | 'webpush';
|
|
7
7
|
/** @deprecated Use PushPlatform. */
|
|
8
8
|
export type NativePushPlatform = PushPlatform;
|
|
@@ -217,13 +217,13 @@ export declare const pushRoutes: <UserType>({ accessTokens, authSessionStore, co
|
|
|
217
217
|
}>;
|
|
218
218
|
error: [];
|
|
219
219
|
}, "delete", "/auth/mobile/push", import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
220
|
-
body: import("typebox").TObject<{
|
|
221
|
-
installationId: import("typebox").TString;
|
|
222
|
-
}>;
|
|
223
220
|
beforeHandle: ({ pushPrincipal, status }: {
|
|
224
221
|
pushPrincipal: AuthPrincipal<UserType> | undefined;
|
|
225
222
|
status: (code: "Unauthorized", body: string) => unknown;
|
|
226
223
|
}) => unknown;
|
|
224
|
+
body: import("typebox").TObject<{
|
|
225
|
+
installationId: import("typebox").TString;
|
|
226
|
+
}>;
|
|
227
227
|
}, {}, "/auth/mobile/push">, import("elysia/types").MergeScopedSchemas<{}, {}, import("elysia").UnwrapRoute<{
|
|
228
228
|
cookie: import("elysia").TCookieObject<{
|
|
229
229
|
user_session_id: import("typebox").TOptional<import("typebox").TTemplateLiteral<"^.*-.*-.*-.*-.*$">>;
|
|
@@ -372,13 +372,13 @@ export declare const pushRoutes: <UserType>({ accessTokens, authSessionStore, co
|
|
|
372
372
|
readonly "Network Authentication Required": 511;
|
|
373
373
|
}[Code] : Code>;
|
|
374
374
|
defer: (fn: import("elysia/types").AfterResponseHandler<NoInfer<import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
375
|
-
body: import("typebox").TObject<{
|
|
376
|
-
installationId: import("typebox").TString;
|
|
377
|
-
}>;
|
|
378
375
|
beforeHandle: ({ pushPrincipal, status }: {
|
|
379
376
|
pushPrincipal: AuthPrincipal<UserType> | undefined;
|
|
380
377
|
status: (code: "Unauthorized", body: string) => unknown;
|
|
381
378
|
}) => unknown;
|
|
379
|
+
body: import("typebox").TObject<{
|
|
380
|
+
installationId: import("typebox").TString;
|
|
381
|
+
}>;
|
|
382
382
|
}, {}, "/auth/mobile/push">, import("elysia/types").MergeScopedSchemas<{}, {}, import("elysia").UnwrapRoute<{
|
|
383
383
|
cookie: import("elysia").TCookieObject<{
|
|
384
384
|
user_session_id: import("typebox").TOptional<import("typebox").TTemplateLiteral<"^.*-.*-.*-.*-.*$">>;
|
|
@@ -572,13 +572,13 @@ export declare const nativePushRoutes: <UserType>({ accessTokens, authSessionSto
|
|
|
572
572
|
}>;
|
|
573
573
|
error: [];
|
|
574
574
|
}, "delete", "/auth/mobile/push", import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
575
|
-
body: import("typebox").TObject<{
|
|
576
|
-
installationId: import("typebox").TString;
|
|
577
|
-
}>;
|
|
578
575
|
beforeHandle: ({ pushPrincipal, status }: {
|
|
579
576
|
pushPrincipal: AuthPrincipal<UserType> | undefined;
|
|
580
577
|
status: (code: "Unauthorized", body: string) => unknown;
|
|
581
578
|
}) => unknown;
|
|
579
|
+
body: import("typebox").TObject<{
|
|
580
|
+
installationId: import("typebox").TString;
|
|
581
|
+
}>;
|
|
582
582
|
}, {}, "/auth/mobile/push">, import("elysia/types").MergeScopedSchemas<{}, {}, import("elysia").UnwrapRoute<{
|
|
583
583
|
cookie: import("elysia").TCookieObject<{
|
|
584
584
|
user_session_id: import("typebox").TOptional<import("typebox").TTemplateLiteral<"^.*-.*-.*-.*-.*$">>;
|
|
@@ -727,13 +727,13 @@ export declare const nativePushRoutes: <UserType>({ accessTokens, authSessionSto
|
|
|
727
727
|
readonly "Network Authentication Required": 511;
|
|
728
728
|
}[Code] : Code>;
|
|
729
729
|
defer: (fn: import("elysia/types").AfterResponseHandler<NoInfer<import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
730
|
-
body: import("typebox").TObject<{
|
|
731
|
-
installationId: import("typebox").TString;
|
|
732
|
-
}>;
|
|
733
730
|
beforeHandle: ({ pushPrincipal, status }: {
|
|
734
731
|
pushPrincipal: AuthPrincipal<UserType> | undefined;
|
|
735
732
|
status: (code: "Unauthorized", body: string) => unknown;
|
|
736
733
|
}) => unknown;
|
|
734
|
+
body: import("typebox").TObject<{
|
|
735
|
+
installationId: import("typebox").TString;
|
|
736
|
+
}>;
|
|
737
737
|
}, {}, "/auth/mobile/push">, import("elysia/types").MergeScopedSchemas<{}, {}, import("elysia").UnwrapRoute<{
|
|
738
738
|
cookie: import("elysia").TCookieObject<{
|
|
739
739
|
user_session_id: import("typebox").TOptional<import("typebox").TTemplateLiteral<"^.*-.*-.*-.*-.*$">>;
|
package/dist/oidc/dpop.d.ts
CHANGED
|
@@ -10,10 +10,14 @@ export declare const verifyDpopNonce: ({ now, nonce, secret }: {
|
|
|
10
10
|
}) => Promise<boolean>;
|
|
11
11
|
export type DpopResult = {
|
|
12
12
|
jkt: string;
|
|
13
|
-
jti
|
|
13
|
+
jti: string;
|
|
14
14
|
};
|
|
15
|
-
export
|
|
15
|
+
export type DpopJti = DpopResult & {
|
|
16
|
+
expiresAt: number;
|
|
17
|
+
};
|
|
18
|
+
export declare const verifyDpopProof: ({ accessToken, consumeJti, htm, htu, isUsedJti, maxAgeMs, now, proof }: {
|
|
16
19
|
accessToken?: string;
|
|
20
|
+
consumeJti?: (jti: DpopJti) => boolean | Promise<boolean>;
|
|
17
21
|
htm: string;
|
|
18
22
|
htu: string;
|
|
19
23
|
isUsedJti?: (jti: string) => boolean | Promise<boolean>;
|
package/dist/oidc/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* through the package root.
|
|
7
7
|
*/
|
|
8
8
|
export type { OidcProviderConfig } from './config';
|
|
9
|
+
export { extractDpopNonceClaim, mintDpopNonce, verifyDpopNonce, verifyDpopProof, type DpopJti, type DpopResult } from './dpop';
|
|
9
10
|
export { generateSigningKey, jwkThumbprint, signJwt, signingVerificationKeys, toPublicJwk, verifyJwt, verifyJwtWithKeys, type SigningKey, type SigningKeyIdentity } from './keys';
|
|
10
11
|
export { revokeOAuthClientCredentials } from './operator';
|
|
11
12
|
export { createNeonAuthorizationCodeStore, createNeonClientAssertionJtiStore, createNeonClientRegistrationTokenStore, createNeonDeviceAuthorizationStore, createNeonInitialAccessTokenStore, createNeonOAuthClientStore, createNeonOidcRefreshTokenStore, createNeonSocketTicketStore, createPostgresAuthorizationCodeStore, createPostgresClientAssertionJtiStore, createPostgresClientRegistrationTokenStore, createPostgresDeviceAuthorizationStore, createPostgresInitialAccessTokenStore, createPostgresOAuthClientStore, createPostgresOidcRefreshTokenStore, createPostgresSocketTicketStore } from './postgresStores';
|
package/dist/oidc/index.js
CHANGED
|
@@ -181,6 +181,9 @@ var init_crypto = __esm(() => {
|
|
|
181
181
|
textDecoder3 = new TextDecoder;
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
+
// src/oidc/dpop.ts
|
|
185
|
+
init_constants();
|
|
186
|
+
|
|
184
187
|
// src/oidc/keys.ts
|
|
185
188
|
var ENCODER = new TextEncoder;
|
|
186
189
|
var ES256 = { hash: "SHA-256", name: "ECDSA" };
|
|
@@ -280,6 +283,128 @@ var verifyJwtWithKeys = async (token, keys) => {
|
|
|
280
283
|
return;
|
|
281
284
|
return verifyJwt(token, key.publicJwk);
|
|
282
285
|
};
|
|
286
|
+
|
|
287
|
+
// src/oidc/dpop.ts
|
|
288
|
+
var DEFAULT_MAX_AGE_MS = 60000;
|
|
289
|
+
var MAX_JTI_LENGTH = 128;
|
|
290
|
+
var SECONDS_TO_MS = 1000;
|
|
291
|
+
var NONCE_WINDOW_SECONDS = 120;
|
|
292
|
+
var NONCE_WINDOW_MS = NONCE_WINDOW_SECONDS * MILLISECONDS_IN_A_SECOND;
|
|
293
|
+
var NONCE_PREVIOUS_WINDOWS_ACCEPTED = 1;
|
|
294
|
+
var hmacSha256 = async (secret, message) => {
|
|
295
|
+
const encoder = new TextEncoder;
|
|
296
|
+
const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
|
|
297
|
+
const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(message));
|
|
298
|
+
return Buffer.from(new Uint8Array(signature)).toString("base64url");
|
|
299
|
+
};
|
|
300
|
+
var extractDpopNonceClaim = (proof) => {
|
|
301
|
+
const [, payloadSegment] = proof.split(".");
|
|
302
|
+
if (payloadSegment === undefined)
|
|
303
|
+
return;
|
|
304
|
+
try {
|
|
305
|
+
const payload = JSON.parse(Buffer.from(payloadSegment, "base64url").toString("utf8"));
|
|
306
|
+
if (typeof payload !== "object" || payload === null)
|
|
307
|
+
return;
|
|
308
|
+
const value = Reflect.get(payload, "nonce");
|
|
309
|
+
return typeof value === "string" ? value : undefined;
|
|
310
|
+
} catch {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
var mintDpopNonce = async ({
|
|
315
|
+
now = Date.now(),
|
|
316
|
+
secret
|
|
317
|
+
}) => {
|
|
318
|
+
const window = Math.floor(now / NONCE_WINDOW_MS);
|
|
319
|
+
return hmacSha256(secret, String(window));
|
|
320
|
+
};
|
|
321
|
+
var verifyDpopNonce = async ({
|
|
322
|
+
now = Date.now(),
|
|
323
|
+
nonce,
|
|
324
|
+
secret
|
|
325
|
+
}) => {
|
|
326
|
+
const currentWindow = Math.floor(now / NONCE_WINDOW_MS);
|
|
327
|
+
const candidates = await Promise.all(Array.from({ length: NONCE_PREVIOUS_WINDOWS_ACCEPTED + 1 }, (_, offset) => hmacSha256(secret, String(currentWindow - offset))));
|
|
328
|
+
return candidates.some((expected) => expected === nonce);
|
|
329
|
+
};
|
|
330
|
+
var decodeHeader = (segment) => {
|
|
331
|
+
try {
|
|
332
|
+
const value = JSON.parse(Buffer.from(segment, "base64url").toString("utf8"));
|
|
333
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
334
|
+
} catch {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
var normalizeHtu = (value, proofClaim = false) => {
|
|
339
|
+
try {
|
|
340
|
+
const url = new URL(String(value));
|
|
341
|
+
if (url.username || url.password || proofClaim && (url.search.length > 0 || url.hash.length > 0))
|
|
342
|
+
return;
|
|
343
|
+
return `${url.origin}${url.pathname}`;
|
|
344
|
+
} catch {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
var isPublicEs256Jwk = (value) => {
|
|
349
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
350
|
+
return false;
|
|
351
|
+
const kty = Reflect.get(value, "kty");
|
|
352
|
+
const crv = Reflect.get(value, "crv");
|
|
353
|
+
const xCoordinate = Reflect.get(value, "x");
|
|
354
|
+
const yCoordinate = Reflect.get(value, "y");
|
|
355
|
+
const privateComponent = Reflect.get(value, "d");
|
|
356
|
+
const alg = Reflect.get(value, "alg");
|
|
357
|
+
return kty === "EC" && crv === "P-256" && typeof xCoordinate === "string" && xCoordinate.length > 0 && typeof yCoordinate === "string" && yCoordinate.length > 0 && privateComponent === undefined && (alg === undefined || alg === "ES256");
|
|
358
|
+
};
|
|
359
|
+
var verifyDpopProof = async ({
|
|
360
|
+
accessToken,
|
|
361
|
+
consumeJti,
|
|
362
|
+
htm,
|
|
363
|
+
htu,
|
|
364
|
+
isUsedJti,
|
|
365
|
+
maxAgeMs = DEFAULT_MAX_AGE_MS,
|
|
366
|
+
now = Date.now(),
|
|
367
|
+
proof
|
|
368
|
+
}) => {
|
|
369
|
+
if (proof === undefined)
|
|
370
|
+
return;
|
|
371
|
+
const segments = proof.split(".");
|
|
372
|
+
if (segments.length !== 3)
|
|
373
|
+
return;
|
|
374
|
+
const [headerSegment] = segments;
|
|
375
|
+
if (headerSegment === undefined)
|
|
376
|
+
return;
|
|
377
|
+
const header = decodeHeader(headerSegment);
|
|
378
|
+
const publicJwk = header === undefined ? undefined : Reflect.get(header, "jwk");
|
|
379
|
+
if (header === undefined || Reflect.get(header, "typ") !== "dpop+jwt" || Reflect.get(header, "alg") !== "ES256" || !isPublicEs256Jwk(publicJwk)) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const verified = await verifyJwt(proof, publicJwk).catch(() => {
|
|
383
|
+
return;
|
|
384
|
+
});
|
|
385
|
+
if (verified === undefined)
|
|
386
|
+
return;
|
|
387
|
+
const { payload } = verified;
|
|
388
|
+
if (accessToken !== undefined) {
|
|
389
|
+
const expectedAth = Buffer.from(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(accessToken))).toString("base64url");
|
|
390
|
+
if (payload.ath !== expectedAth)
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const iatMs = typeof payload.iat === "number" ? payload.iat * SECONDS_TO_MS : 0;
|
|
394
|
+
const claimedHtu = normalizeHtu(payload.htu, true);
|
|
395
|
+
const expectedHtu = normalizeHtu(htu);
|
|
396
|
+
const jti = typeof payload.jti === "string" ? payload.jti : undefined;
|
|
397
|
+
if (payload.htm !== htm || claimedHtu === undefined || expectedHtu === undefined || claimedHtu !== expectedHtu || iatMs === 0 || Math.abs(now - iatMs) > maxAgeMs || jti === undefined || jti.length === 0 || jti.length > MAX_JTI_LENGTH) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
const jkt = await jwkThumbprint(publicJwk);
|
|
401
|
+
if (isUsedJti !== undefined && await isUsedJti(jti)) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (consumeJti !== undefined && !await consumeJti({ expiresAt: iatMs + maxAgeMs, jkt, jti }))
|
|
405
|
+
return;
|
|
406
|
+
return { jkt, jti };
|
|
407
|
+
};
|
|
283
408
|
// src/oidc/operator.ts
|
|
284
409
|
var operatorDelete = (store, storeName) => {
|
|
285
410
|
if (!store.deleteForClient)
|
|
@@ -12788,13 +12913,17 @@ var issueSocketTicket = async ({
|
|
|
12788
12913
|
export {
|
|
12789
12914
|
verifyJwtWithKeys,
|
|
12790
12915
|
verifyJwt,
|
|
12916
|
+
verifyDpopProof,
|
|
12917
|
+
verifyDpopNonce,
|
|
12791
12918
|
toPublicJwk,
|
|
12792
12919
|
signingVerificationKeys,
|
|
12793
12920
|
signJwt,
|
|
12794
12921
|
revokeOAuthClientCredentials,
|
|
12922
|
+
mintDpopNonce,
|
|
12795
12923
|
jwkThumbprint,
|
|
12796
12924
|
issueSocketTicket,
|
|
12797
12925
|
generateSigningKey,
|
|
12926
|
+
extractDpopNonceClaim,
|
|
12798
12927
|
createPostgresSocketTicketStore,
|
|
12799
12928
|
createPostgresOidcRefreshTokenStore,
|
|
12800
12929
|
createPostgresOAuthClientStore,
|
|
@@ -12815,5 +12944,5 @@ export {
|
|
|
12815
12944
|
consumeSocketTicket
|
|
12816
12945
|
};
|
|
12817
12946
|
|
|
12818
|
-
//# debugId=
|
|
12947
|
+
//# debugId=9914FF0D8636BBE564756E2164756E21
|
|
12819
12948
|
//# sourceMappingURL=index.js.map
|