@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
|
@@ -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/agents/routes.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export declare const agentAuthPlugin: (config?: AgentAuthConfig) => Elysia<"", "
|
|
|
35
35
|
scopes_supported: string[];
|
|
36
36
|
resource_name?: string | undefined;
|
|
37
37
|
resource_logo_uri?: string | undefined;
|
|
38
|
+
dpop_bound_access_tokens_required?: boolean | undefined;
|
|
38
39
|
authorization_servers: string[];
|
|
39
40
|
bearer_methods_supported: string[];
|
|
40
41
|
};
|
|
@@ -149,6 +150,7 @@ export declare const agentAuthRoutes: (config?: AgentAuthConfig) => Elysia<"", "
|
|
|
149
150
|
scopes_supported: string[];
|
|
150
151
|
resource_name?: string | undefined;
|
|
151
152
|
resource_logo_uri?: string | undefined;
|
|
153
|
+
dpop_bound_access_tokens_required?: boolean | undefined;
|
|
152
154
|
authorization_servers: string[];
|
|
153
155
|
bearer_methods_supported: string[];
|
|
154
156
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -3759,6 +3759,7 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
|
|
|
3759
3759
|
scopes_supported: string[];
|
|
3760
3760
|
resource_name?: string | undefined;
|
|
3761
3761
|
resource_logo_uri?: string | undefined;
|
|
3762
|
+
dpop_bound_access_tokens_required?: boolean | undefined;
|
|
3762
3763
|
authorization_servers: string[];
|
|
3763
3764
|
bearer_methods_supported: string[];
|
|
3764
3765
|
};
|
|
@@ -3991,7 +3992,7 @@ export { oidcProviderRoutes } from './oidc/routes';
|
|
|
3991
3992
|
export { generateSigningKey, jwkThumbprint, signJwt, signingVerificationKeys, toPublicJwk, verifyJwt, verifyJwtWithKeys } from './oidc/keys';
|
|
3992
3993
|
export type { SigningKey, SigningKeyIdentity } from './oidc/keys';
|
|
3993
3994
|
export { extractDpopNonceClaim, mintDpopNonce, verifyDpopNonce, verifyDpopProof } from './oidc/dpop';
|
|
3994
|
-
export type { DpopResult } from './oidc/dpop';
|
|
3995
|
+
export type { DpopJti, DpopResult } from './oidc/dpop';
|
|
3995
3996
|
export { CLIENT_ASSERTION_TYPE, verifyClientAssertion, verifyJwtSignedByClient } from './oidc/clientAuth';
|
|
3996
3997
|
export { parseSignedRequestObject } from './oidc/jar';
|
|
3997
3998
|
export type { JarParseResult } from './oidc/jar';
|
package/dist/index.js
CHANGED
|
@@ -3260,6 +3260,7 @@ var DEFAULT_AGENT_RESOURCE_METADATA_ROUTE = "/.well-known/oauth-protected-resour
|
|
|
3260
3260
|
var agentProtectedResourceMetadata = (config) => ({
|
|
3261
3261
|
authorization_servers: [config.authorizationServer],
|
|
3262
3262
|
bearer_methods_supported: ["header"],
|
|
3263
|
+
...config.dpopBoundAccessTokensRequired === true ? { dpop_bound_access_tokens_required: true } : {},
|
|
3263
3264
|
...config.logoUri === undefined ? {} : { resource_logo_uri: config.logoUri },
|
|
3264
3265
|
...config.resourceName === undefined ? {} : { resource_name: config.resourceName },
|
|
3265
3266
|
resource: config.resource,
|
|
@@ -6191,8 +6192,8 @@ var createMfaGate = ({ getUserId, mfaStore }) => async (user) => isMfaEnrolled(a
|
|
|
6191
6192
|
|
|
6192
6193
|
// src/nativePush.ts
|
|
6193
6194
|
import { Elysia as Elysia17, t as t11 } from "elysia";
|
|
6194
|
-
var DEFAULT_PUSH_ROUTE = "/auth/push";
|
|
6195
6195
|
var DEFAULT_NATIVE_PUSH_ROUTE = "/auth/mobile/push";
|
|
6196
|
+
var DEFAULT_PUSH_ROUTE = "/auth/push";
|
|
6196
6197
|
var requireServerText = (value, field) => {
|
|
6197
6198
|
const normalized = value.trim();
|
|
6198
6199
|
if (!normalized)
|
|
@@ -6246,9 +6247,11 @@ var pushRoutes = ({
|
|
|
6246
6247
|
}
|
|
6247
6248
|
return true;
|
|
6248
6249
|
};
|
|
6250
|
+
const installationIdSchema = t11.Optional(t11.String({ maxLength: 128, minLength: 1 }));
|
|
6251
|
+
const localeSchema = t11.Optional(t11.String({ maxLength: 64, minLength: 1 }));
|
|
6249
6252
|
const commonRegistrationFields = {
|
|
6250
|
-
installationId:
|
|
6251
|
-
locale:
|
|
6253
|
+
installationId: installationIdSchema,
|
|
6254
|
+
locale: localeSchema
|
|
6252
6255
|
};
|
|
6253
6256
|
const registrationBody = t11.Union([
|
|
6254
6257
|
t11.Object({
|
|
@@ -6268,18 +6271,20 @@ var pushRoutes = ({
|
|
|
6268
6271
|
})
|
|
6269
6272
|
})
|
|
6270
6273
|
]);
|
|
6274
|
+
const requirePushPrincipal = ({
|
|
6275
|
+
pushPrincipal,
|
|
6276
|
+
status
|
|
6277
|
+
}) => pushPrincipal ? undefined : status("Unauthorized", "User is not authenticated");
|
|
6271
6278
|
const registrationOptions = {
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
pushPrincipal,
|
|
6275
|
-
status
|
|
6276
|
-
}) => pushPrincipal ? undefined : status("Unauthorized", "User is not authenticated")
|
|
6279
|
+
beforeHandle: requirePushPrincipal,
|
|
6280
|
+
body: registrationBody
|
|
6277
6281
|
};
|
|
6282
|
+
const removalBody = t11.Object({
|
|
6283
|
+
installationId: t11.String({ maxLength: 128, minLength: 1 })
|
|
6284
|
+
});
|
|
6278
6285
|
const removalOptions = {
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
}),
|
|
6282
|
-
beforeHandle: registrationOptions.beforeHandle
|
|
6286
|
+
beforeHandle: requirePushPrincipal,
|
|
6287
|
+
body: removalBody
|
|
6283
6288
|
};
|
|
6284
6289
|
return new Elysia17({ name: "@absolutejs/auth/push" }).use(sessionStore()).guard({
|
|
6285
6290
|
cookie: t11.Cookie({ user_session_id: userSessionIdTypebox }),
|
|
@@ -8086,6 +8091,7 @@ var verifyCertificateBoundToken = async ({
|
|
|
8086
8091
|
// src/oidc/dpop.ts
|
|
8087
8092
|
init_constants();
|
|
8088
8093
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
8094
|
+
var MAX_JTI_LENGTH = 128;
|
|
8089
8095
|
var SECONDS_TO_MS = 1000;
|
|
8090
8096
|
var NONCE_WINDOW_SECONDS = 120;
|
|
8091
8097
|
var NONCE_WINDOW_MS = NONCE_WINDOW_SECONDS * MILLISECONDS_IN_A_SECOND;
|
|
@@ -8126,17 +8132,38 @@ var verifyDpopNonce = async ({
|
|
|
8126
8132
|
const candidates = await Promise.all(Array.from({ length: NONCE_PREVIOUS_WINDOWS_ACCEPTED + 1 }, (_, offset) => hmacSha2562(secret, String(currentWindow - offset))));
|
|
8127
8133
|
return candidates.some((expected) => expected === nonce);
|
|
8128
8134
|
};
|
|
8129
|
-
var decodeHeader = (segment) =>
|
|
8130
|
-
|
|
8135
|
+
var decodeHeader = (segment) => {
|
|
8136
|
+
try {
|
|
8137
|
+
const value = JSON.parse(Buffer.from(segment, "base64url").toString("utf8"));
|
|
8138
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
8139
|
+
} catch {
|
|
8140
|
+
return;
|
|
8141
|
+
}
|
|
8142
|
+
};
|
|
8143
|
+
var normalizeHtu = (value, proofClaim = false) => {
|
|
8131
8144
|
try {
|
|
8132
8145
|
const url = new URL(String(value));
|
|
8146
|
+
if (url.username || url.password || proofClaim && (url.search.length > 0 || url.hash.length > 0))
|
|
8147
|
+
return;
|
|
8133
8148
|
return `${url.origin}${url.pathname}`;
|
|
8134
8149
|
} catch {
|
|
8135
|
-
return
|
|
8150
|
+
return;
|
|
8136
8151
|
}
|
|
8137
8152
|
};
|
|
8153
|
+
var isPublicEs256Jwk = (value) => {
|
|
8154
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
8155
|
+
return false;
|
|
8156
|
+
const kty = Reflect.get(value, "kty");
|
|
8157
|
+
const crv = Reflect.get(value, "crv");
|
|
8158
|
+
const xCoordinate = Reflect.get(value, "x");
|
|
8159
|
+
const yCoordinate = Reflect.get(value, "y");
|
|
8160
|
+
const privateComponent = Reflect.get(value, "d");
|
|
8161
|
+
const alg = Reflect.get(value, "alg");
|
|
8162
|
+
return kty === "EC" && crv === "P-256" && typeof xCoordinate === "string" && xCoordinate.length > 0 && typeof yCoordinate === "string" && yCoordinate.length > 0 && privateComponent === undefined && (alg === undefined || alg === "ES256");
|
|
8163
|
+
};
|
|
8138
8164
|
var verifyDpopProof = async ({
|
|
8139
8165
|
accessToken,
|
|
8166
|
+
consumeJti,
|
|
8140
8167
|
htm,
|
|
8141
8168
|
htu,
|
|
8142
8169
|
isUsedJti,
|
|
@@ -8146,14 +8173,20 @@ var verifyDpopProof = async ({
|
|
|
8146
8173
|
}) => {
|
|
8147
8174
|
if (proof === undefined)
|
|
8148
8175
|
return;
|
|
8149
|
-
const
|
|
8176
|
+
const segments = proof.split(".");
|
|
8177
|
+
if (segments.length !== 3)
|
|
8178
|
+
return;
|
|
8179
|
+
const [headerSegment] = segments;
|
|
8150
8180
|
if (headerSegment === undefined)
|
|
8151
8181
|
return;
|
|
8152
8182
|
const header = decodeHeader(headerSegment);
|
|
8153
|
-
|
|
8183
|
+
const publicJwk = header === undefined ? undefined : Reflect.get(header, "jwk");
|
|
8184
|
+
if (header === undefined || Reflect.get(header, "typ") !== "dpop+jwt" || Reflect.get(header, "alg") !== "ES256" || !isPublicEs256Jwk(publicJwk)) {
|
|
8154
8185
|
return;
|
|
8155
8186
|
}
|
|
8156
|
-
const verified = await verifyJwt(proof,
|
|
8187
|
+
const verified = await verifyJwt(proof, publicJwk).catch(() => {
|
|
8188
|
+
return;
|
|
8189
|
+
});
|
|
8157
8190
|
if (verified === undefined)
|
|
8158
8191
|
return;
|
|
8159
8192
|
const { payload } = verified;
|
|
@@ -8163,14 +8196,19 @@ var verifyDpopProof = async ({
|
|
|
8163
8196
|
return;
|
|
8164
8197
|
}
|
|
8165
8198
|
const iatMs = typeof payload.iat === "number" ? payload.iat * SECONDS_TO_MS : 0;
|
|
8166
|
-
|
|
8199
|
+
const claimedHtu = normalizeHtu(payload.htu, true);
|
|
8200
|
+
const expectedHtu = normalizeHtu(htu);
|
|
8201
|
+
const jti = typeof payload.jti === "string" ? payload.jti : undefined;
|
|
8202
|
+
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
8203
|
return;
|
|
8168
8204
|
}
|
|
8169
|
-
const
|
|
8170
|
-
if (
|
|
8205
|
+
const jkt = await jwkThumbprint(publicJwk);
|
|
8206
|
+
if (isUsedJti !== undefined && await isUsedJti(jti)) {
|
|
8171
8207
|
return;
|
|
8172
8208
|
}
|
|
8173
|
-
|
|
8209
|
+
if (consumeJti !== undefined && !await consumeJti({ expiresAt: iatMs + maxAgeMs, jkt, jti }))
|
|
8210
|
+
return;
|
|
8211
|
+
return { jkt, jti };
|
|
8174
8212
|
};
|
|
8175
8213
|
|
|
8176
8214
|
// src/oidc/logout.ts
|
|
@@ -8909,7 +8947,7 @@ var oidcProviderRoutes = (config) => {
|
|
|
8909
8947
|
"dpop-nonce": fresh,
|
|
8910
8948
|
"www-authenticate": 'DPoP error="use_dpop_nonce"'
|
|
8911
8949
|
},
|
|
8912
|
-
status:
|
|
8950
|
+
status: HTTP_BAD_REQUEST3
|
|
8913
8951
|
});
|
|
8914
8952
|
};
|
|
8915
8953
|
const grantAuthorizationCode = async (client, body, dpop, clientCertThumbprint) => {
|
|
@@ -36606,6 +36644,7 @@ var readAudience = (audience) => {
|
|
|
36606
36644
|
};
|
|
36607
36645
|
var createOidcAgentCredentialVerifier = ({
|
|
36608
36646
|
issuer,
|
|
36647
|
+
consumeDpopJti,
|
|
36609
36648
|
isUsedDpopJti,
|
|
36610
36649
|
maxDpopAgeMs,
|
|
36611
36650
|
publicJwk,
|
|
@@ -36634,6 +36673,7 @@ var createOidcAgentCredentialVerifier = ({
|
|
|
36634
36673
|
return;
|
|
36635
36674
|
const proof = await verifyDpopProof({
|
|
36636
36675
|
accessToken: token,
|
|
36676
|
+
consumeJti: consumeDpopJti,
|
|
36637
36677
|
htm: request.method,
|
|
36638
36678
|
htu: request.url,
|
|
36639
36679
|
isUsedJti: isUsedDpopJti,
|
|
@@ -40973,5 +41013,5 @@ export {
|
|
|
40973
41013
|
ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV
|
|
40974
41014
|
};
|
|
40975
41015
|
|
|
40976
|
-
//# debugId=
|
|
41016
|
+
//# debugId=6230674639E5BA6B64756E2164756E21
|
|
40977
41017
|
//# sourceMappingURL=index.js.map
|