@absolutejs/auth 0.75.0 → 0.75.1
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/index.js +46 -11
- package/dist/agents/index.js.map +4 -4
- package/dist/agents/oidcAdapter.d.ts +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +63 -24
- package/dist/index.js.map +7 -7
- 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 +63 -24
- package/dist/server.js.map +7 -7
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type SigningKeyIdentity } from '../oidc/keys';
|
|
2
|
+
import { type DpopJti } from '../oidc/dpop';
|
|
2
3
|
import type { AgentCredentialVerifier } from './types';
|
|
3
4
|
type OidcAgentCredentialVerifierKeys = {
|
|
4
5
|
publicJwk: JsonWebKey;
|
|
@@ -10,8 +11,9 @@ type OidcAgentCredentialVerifierKeys = {
|
|
|
10
11
|
/** Adapter for Absolute Auth's RFC 9068-style JWT access tokens. It validates
|
|
11
12
|
* signature, issuer, audience, expiry, and extracts the OAuth client as the
|
|
12
13
|
* agent identity while retaining `sub` as the authorizing user. */
|
|
13
|
-
export declare const createOidcAgentCredentialVerifier: ({ issuer, isUsedDpopJti, maxDpopAgeMs, publicJwk, publicKeys, requireDpop, resource }: {
|
|
14
|
+
export declare const createOidcAgentCredentialVerifier: ({ issuer, consumeDpopJti, isUsedDpopJti, maxDpopAgeMs, publicJwk, publicKeys, requireDpop, resource }: {
|
|
14
15
|
issuer: string;
|
|
16
|
+
consumeDpopJti?: (jti: DpopJti) => boolean | Promise<boolean>;
|
|
15
17
|
isUsedDpopJti?: (jti: string) => boolean | Promise<boolean>;
|
|
16
18
|
maxDpopAgeMs?: number;
|
|
17
19
|
requireDpop?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -3991,7 +3991,7 @@ export { oidcProviderRoutes } from './oidc/routes';
|
|
|
3991
3991
|
export { generateSigningKey, jwkThumbprint, signJwt, signingVerificationKeys, toPublicJwk, verifyJwt, verifyJwtWithKeys } from './oidc/keys';
|
|
3992
3992
|
export type { SigningKey, SigningKeyIdentity } from './oidc/keys';
|
|
3993
3993
|
export { extractDpopNonceClaim, mintDpopNonce, verifyDpopNonce, verifyDpopProof } from './oidc/dpop';
|
|
3994
|
-
export type { DpopResult } from './oidc/dpop';
|
|
3994
|
+
export type { DpopJti, DpopResult } from './oidc/dpop';
|
|
3995
3995
|
export { CLIENT_ASSERTION_TYPE, verifyClientAssertion, verifyJwtSignedByClient } from './oidc/clientAuth';
|
|
3996
3996
|
export { parseSignedRequestObject } from './oidc/jar';
|
|
3997
3997
|
export type { JarParseResult } from './oidc/jar';
|
package/dist/index.js
CHANGED
|
@@ -6191,8 +6191,8 @@ var createMfaGate = ({ getUserId, mfaStore }) => async (user) => isMfaEnrolled(a
|
|
|
6191
6191
|
|
|
6192
6192
|
// src/nativePush.ts
|
|
6193
6193
|
import { Elysia as Elysia17, t as t11 } from "elysia";
|
|
6194
|
-
var DEFAULT_PUSH_ROUTE = "/auth/push";
|
|
6195
6194
|
var DEFAULT_NATIVE_PUSH_ROUTE = "/auth/mobile/push";
|
|
6195
|
+
var DEFAULT_PUSH_ROUTE = "/auth/push";
|
|
6196
6196
|
var requireServerText = (value, field) => {
|
|
6197
6197
|
const normalized = value.trim();
|
|
6198
6198
|
if (!normalized)
|
|
@@ -6246,9 +6246,11 @@ var pushRoutes = ({
|
|
|
6246
6246
|
}
|
|
6247
6247
|
return true;
|
|
6248
6248
|
};
|
|
6249
|
+
const installationIdSchema = t11.Optional(t11.String({ maxLength: 128, minLength: 1 }));
|
|
6250
|
+
const localeSchema = t11.Optional(t11.String({ maxLength: 64, minLength: 1 }));
|
|
6249
6251
|
const commonRegistrationFields = {
|
|
6250
|
-
installationId:
|
|
6251
|
-
locale:
|
|
6252
|
+
installationId: installationIdSchema,
|
|
6253
|
+
locale: localeSchema
|
|
6252
6254
|
};
|
|
6253
6255
|
const registrationBody = t11.Union([
|
|
6254
6256
|
t11.Object({
|
|
@@ -6268,18 +6270,20 @@ var pushRoutes = ({
|
|
|
6268
6270
|
})
|
|
6269
6271
|
})
|
|
6270
6272
|
]);
|
|
6273
|
+
const requirePushPrincipal = ({
|
|
6274
|
+
pushPrincipal,
|
|
6275
|
+
status
|
|
6276
|
+
}) => pushPrincipal ? undefined : status("Unauthorized", "User is not authenticated");
|
|
6271
6277
|
const registrationOptions = {
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
pushPrincipal,
|
|
6275
|
-
status
|
|
6276
|
-
}) => pushPrincipal ? undefined : status("Unauthorized", "User is not authenticated")
|
|
6278
|
+
beforeHandle: requirePushPrincipal,
|
|
6279
|
+
body: registrationBody
|
|
6277
6280
|
};
|
|
6281
|
+
const removalBody = t11.Object({
|
|
6282
|
+
installationId: t11.String({ maxLength: 128, minLength: 1 })
|
|
6283
|
+
});
|
|
6278
6284
|
const removalOptions = {
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
}),
|
|
6282
|
-
beforeHandle: registrationOptions.beforeHandle
|
|
6285
|
+
beforeHandle: requirePushPrincipal,
|
|
6286
|
+
body: removalBody
|
|
6283
6287
|
};
|
|
6284
6288
|
return new Elysia17({ name: "@absolutejs/auth/push" }).use(sessionStore()).guard({
|
|
6285
6289
|
cookie: t11.Cookie({ user_session_id: userSessionIdTypebox }),
|
|
@@ -8086,6 +8090,7 @@ var verifyCertificateBoundToken = async ({
|
|
|
8086
8090
|
// src/oidc/dpop.ts
|
|
8087
8091
|
init_constants();
|
|
8088
8092
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
8093
|
+
var MAX_JTI_LENGTH = 128;
|
|
8089
8094
|
var SECONDS_TO_MS = 1000;
|
|
8090
8095
|
var NONCE_WINDOW_SECONDS = 120;
|
|
8091
8096
|
var NONCE_WINDOW_MS = NONCE_WINDOW_SECONDS * MILLISECONDS_IN_A_SECOND;
|
|
@@ -8126,17 +8131,38 @@ var verifyDpopNonce = async ({
|
|
|
8126
8131
|
const candidates = await Promise.all(Array.from({ length: NONCE_PREVIOUS_WINDOWS_ACCEPTED + 1 }, (_, offset) => hmacSha2562(secret, String(currentWindow - offset))));
|
|
8127
8132
|
return candidates.some((expected) => expected === nonce);
|
|
8128
8133
|
};
|
|
8129
|
-
var decodeHeader = (segment) =>
|
|
8130
|
-
|
|
8134
|
+
var decodeHeader = (segment) => {
|
|
8135
|
+
try {
|
|
8136
|
+
const value = JSON.parse(Buffer.from(segment, "base64url").toString("utf8"));
|
|
8137
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
8138
|
+
} catch {
|
|
8139
|
+
return;
|
|
8140
|
+
}
|
|
8141
|
+
};
|
|
8142
|
+
var normalizeHtu = (value, proofClaim = false) => {
|
|
8131
8143
|
try {
|
|
8132
8144
|
const url = new URL(String(value));
|
|
8145
|
+
if (url.username || url.password || proofClaim && (url.search.length > 0 || url.hash.length > 0))
|
|
8146
|
+
return;
|
|
8133
8147
|
return `${url.origin}${url.pathname}`;
|
|
8134
8148
|
} catch {
|
|
8135
|
-
return
|
|
8149
|
+
return;
|
|
8136
8150
|
}
|
|
8137
8151
|
};
|
|
8152
|
+
var isPublicEs256Jwk = (value) => {
|
|
8153
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
8154
|
+
return false;
|
|
8155
|
+
const kty = Reflect.get(value, "kty");
|
|
8156
|
+
const crv = Reflect.get(value, "crv");
|
|
8157
|
+
const xCoordinate = Reflect.get(value, "x");
|
|
8158
|
+
const yCoordinate = Reflect.get(value, "y");
|
|
8159
|
+
const privateComponent = Reflect.get(value, "d");
|
|
8160
|
+
const alg = Reflect.get(value, "alg");
|
|
8161
|
+
return kty === "EC" && crv === "P-256" && typeof xCoordinate === "string" && xCoordinate.length > 0 && typeof yCoordinate === "string" && yCoordinate.length > 0 && privateComponent === undefined && (alg === undefined || alg === "ES256");
|
|
8162
|
+
};
|
|
8138
8163
|
var verifyDpopProof = async ({
|
|
8139
8164
|
accessToken,
|
|
8165
|
+
consumeJti,
|
|
8140
8166
|
htm,
|
|
8141
8167
|
htu,
|
|
8142
8168
|
isUsedJti,
|
|
@@ -8146,14 +8172,20 @@ var verifyDpopProof = async ({
|
|
|
8146
8172
|
}) => {
|
|
8147
8173
|
if (proof === undefined)
|
|
8148
8174
|
return;
|
|
8149
|
-
const
|
|
8175
|
+
const segments = proof.split(".");
|
|
8176
|
+
if (segments.length !== 3)
|
|
8177
|
+
return;
|
|
8178
|
+
const [headerSegment] = segments;
|
|
8150
8179
|
if (headerSegment === undefined)
|
|
8151
8180
|
return;
|
|
8152
8181
|
const header = decodeHeader(headerSegment);
|
|
8153
|
-
|
|
8182
|
+
const publicJwk = header === undefined ? undefined : Reflect.get(header, "jwk");
|
|
8183
|
+
if (header === undefined || Reflect.get(header, "typ") !== "dpop+jwt" || Reflect.get(header, "alg") !== "ES256" || !isPublicEs256Jwk(publicJwk)) {
|
|
8154
8184
|
return;
|
|
8155
8185
|
}
|
|
8156
|
-
const verified = await verifyJwt(proof,
|
|
8186
|
+
const verified = await verifyJwt(proof, publicJwk).catch(() => {
|
|
8187
|
+
return;
|
|
8188
|
+
});
|
|
8157
8189
|
if (verified === undefined)
|
|
8158
8190
|
return;
|
|
8159
8191
|
const { payload } = verified;
|
|
@@ -8163,14 +8195,19 @@ var verifyDpopProof = async ({
|
|
|
8163
8195
|
return;
|
|
8164
8196
|
}
|
|
8165
8197
|
const iatMs = typeof payload.iat === "number" ? payload.iat * SECONDS_TO_MS : 0;
|
|
8166
|
-
|
|
8198
|
+
const claimedHtu = normalizeHtu(payload.htu, true);
|
|
8199
|
+
const expectedHtu = normalizeHtu(htu);
|
|
8200
|
+
const jti = typeof payload.jti === "string" ? payload.jti : undefined;
|
|
8201
|
+
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) {
|
|
8167
8202
|
return;
|
|
8168
8203
|
}
|
|
8169
|
-
const
|
|
8170
|
-
if (
|
|
8204
|
+
const jkt = await jwkThumbprint(publicJwk);
|
|
8205
|
+
if (isUsedJti !== undefined && await isUsedJti(jti)) {
|
|
8171
8206
|
return;
|
|
8172
8207
|
}
|
|
8173
|
-
|
|
8208
|
+
if (consumeJti !== undefined && !await consumeJti({ expiresAt: iatMs + maxAgeMs, jkt, jti }))
|
|
8209
|
+
return;
|
|
8210
|
+
return { jkt, jti };
|
|
8174
8211
|
};
|
|
8175
8212
|
|
|
8176
8213
|
// src/oidc/logout.ts
|
|
@@ -8909,7 +8946,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
8909
8946
|
"dpop-nonce": fresh,
|
|
8910
8947
|
"www-authenticate": 'DPoP error="use_dpop_nonce"'
|
|
8911
8948
|
},
|
|
8912
|
-
status:
|
|
8949
|
+
status: HTTP_BAD_REQUEST3
|
|
8913
8950
|
});
|
|
8914
8951
|
};
|
|
8915
8952
|
const grantAuthorizationCode = async (client, body, dpop, clientCertThumbprint) => {
|
|
@@ -36606,6 +36643,7 @@ var readAudience = (audience) => {
|
|
|
36606
36643
|
};
|
|
36607
36644
|
var createOidcAgentCredentialVerifier = ({
|
|
36608
36645
|
issuer,
|
|
36646
|
+
consumeDpopJti,
|
|
36609
36647
|
isUsedDpopJti,
|
|
36610
36648
|
maxDpopAgeMs,
|
|
36611
36649
|
publicJwk,
|
|
@@ -36634,6 +36672,7 @@ var createOidcAgentCredentialVerifier = ({
|
|
|
36634
36672
|
return;
|
|
36635
36673
|
const proof = await verifyDpopProof({
|
|
36636
36674
|
accessToken: token,
|
|
36675
|
+
consumeJti: consumeDpopJti,
|
|
36637
36676
|
htm: request.method,
|
|
36638
36677
|
htu: request.url,
|
|
36639
36678
|
isUsedJti: isUsedDpopJti,
|
|
@@ -40973,5 +41012,5 @@ export {
|
|
|
40973
41012
|
ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV
|
|
40974
41013
|
};
|
|
40975
41014
|
|
|
40976
|
-
//# debugId=
|
|
41015
|
+
//# debugId=1BF002329763FE6764756E2164756E21
|
|
40977
41016
|
//# sourceMappingURL=index.js.map
|