@absolutejs/auth 0.29.0-beta.1 → 0.29.0-beta.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/dist/index.d.ts +5 -2
- package/dist/index.js +189 -9
- package/dist/index.js.map +9 -8
- package/dist/oidc/clientAuth.d.ts +8 -0
- package/dist/oidc/config.d.ts +2 -1
- package/dist/oidc/inMemoryStores.d.ts +2 -1
- package/dist/oidc/postgresStores.d.ts +122 -1
- package/dist/oidc/routes.d.ts +2 -0
- package/dist/oidc/types.d.ts +5 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -13488,6 +13488,8 @@ export declare const auth: <UserType>({ providersConfiguration, authorizeRoute,
|
|
|
13488
13488
|
grant_type?: string | undefined;
|
|
13489
13489
|
code?: string | undefined;
|
|
13490
13490
|
redirect_uri?: string | undefined;
|
|
13491
|
+
client_assertion?: string | undefined;
|
|
13492
|
+
client_assertion_type?: string | undefined;
|
|
13491
13493
|
code_verifier?: string | undefined;
|
|
13492
13494
|
subject_token?: string | undefined;
|
|
13493
13495
|
subject_token_type?: string | undefined;
|
|
@@ -14900,9 +14902,10 @@ export { generateSigningKey, jwkThumbprint, signJwt, toPublicJwk, verifyJwt } fr
|
|
|
14900
14902
|
export type { SigningKey } from './oidc/keys';
|
|
14901
14903
|
export { verifyDpopProof } from './oidc/dpop';
|
|
14902
14904
|
export type { DpopResult } from './oidc/dpop';
|
|
14903
|
-
export {
|
|
14905
|
+
export { CLIENT_ASSERTION_TYPE, verifyClientAssertion } from './oidc/clientAuth';
|
|
14906
|
+
export { createInMemoryAuthorizationCodeStore, createInMemoryClientAssertionJtiStore, createInMemoryDeviceAuthorizationStore, createInMemoryLogoutDeliveryStore, createInMemoryOAuthClientStore, createInMemoryOidcRefreshTokenStore } from './oidc/inMemoryStores';
|
|
14904
14907
|
export { fanOutBackchannelLogout, mintLogoutToken, resolvePostLogoutRedirect, verifyIdTokenHint } from './oidc/logout';
|
|
14905
|
-
export { createNeonAuthorizationCodeStore, createNeonDeviceAuthorizationStore, createNeonLogoutDeliveryStore, createNeonOAuthClientStore, createNeonOidcRefreshTokenStore, createPostgresAuthorizationCodeStore, createPostgresDeviceAuthorizationStore, createPostgresLogoutDeliveryStore, createPostgresOAuthClientStore, createPostgresOidcRefreshTokenStore, oauthClientsTable, oauthCodesTable, oauthDeviceAuthorizationsTable, oauthLogoutDeliveriesTable, oauthRefreshTokensTable } from './oidc/postgresStores';
|
|
14908
|
+
export { createNeonAuthorizationCodeStore, createNeonClientAssertionJtiStore, createNeonDeviceAuthorizationStore, createNeonLogoutDeliveryStore, createNeonOAuthClientStore, createNeonOidcRefreshTokenStore, createPostgresAuthorizationCodeStore, createPostgresClientAssertionJtiStore, createPostgresDeviceAuthorizationStore, createPostgresLogoutDeliveryStore, createPostgresOAuthClientStore, createPostgresOidcRefreshTokenStore, oauthClientAssertionJtisTable, oauthClientsTable, oauthCodesTable, oauthDeviceAuthorizationsTable, oauthLogoutDeliveriesTable, oauthRefreshTokensTable } from './oidc/postgresStores';
|
|
14906
14909
|
export * from './adaptive/config';
|
|
14907
14910
|
export * from './adaptive/fingerprint';
|
|
14908
14911
|
export * from './adaptive/types';
|
package/dist/index.js
CHANGED
|
@@ -4452,6 +4452,105 @@ var exchangeDeviceCode = async ({
|
|
|
4452
4452
|
return { ...tokenSet, ok: true };
|
|
4453
4453
|
};
|
|
4454
4454
|
|
|
4455
|
+
// src/oidc/clientAuth.ts
|
|
4456
|
+
var CLIENT_ASSERTION_TYPE = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
|
4457
|
+
var MAX_ASSERTION_LIFETIME_MINUTES = 5;
|
|
4458
|
+
var SECONDS_PER_MINUTE = 60;
|
|
4459
|
+
var MAX_ASSERTION_LIFETIME_MS = MAX_ASSERTION_LIFETIME_MINUTES * SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
|
|
4460
|
+
var jwksCache = new Map;
|
|
4461
|
+
var JWKS_CACHE_TTL_MS = SECONDS_PER_MINUTE * MILLISECONDS_IN_A_SECOND;
|
|
4462
|
+
var JWKS_FETCH_TIMEOUT_SECONDS = 5;
|
|
4463
|
+
var JWKS_FETCH_TIMEOUT_MS = JWKS_FETCH_TIMEOUT_SECONDS * MILLISECONDS_IN_A_SECOND;
|
|
4464
|
+
var fetchJwksUri = async (jwksUri) => {
|
|
4465
|
+
const cached = jwksCache.get(jwksUri);
|
|
4466
|
+
if (cached && Date.now() - cached.fetchedAt < JWKS_CACHE_TTL_MS) {
|
|
4467
|
+
return cached.jwks;
|
|
4468
|
+
}
|
|
4469
|
+
try {
|
|
4470
|
+
const response = await fetch(jwksUri, {
|
|
4471
|
+
signal: AbortSignal.timeout(JWKS_FETCH_TIMEOUT_MS)
|
|
4472
|
+
});
|
|
4473
|
+
if (!response.ok)
|
|
4474
|
+
return;
|
|
4475
|
+
const body = await response.json();
|
|
4476
|
+
if (!Array.isArray(body.keys))
|
|
4477
|
+
return;
|
|
4478
|
+
jwksCache.set(jwksUri, { fetchedAt: Date.now(), jwks: body.keys });
|
|
4479
|
+
return body.keys;
|
|
4480
|
+
} catch {
|
|
4481
|
+
return;
|
|
4482
|
+
}
|
|
4483
|
+
};
|
|
4484
|
+
var resolveClientJwks = async (client) => {
|
|
4485
|
+
if (client.jwks && client.jwks.length > 0)
|
|
4486
|
+
return client.jwks;
|
|
4487
|
+
if (client.jwksUri !== undefined)
|
|
4488
|
+
return fetchJwksUri(client.jwksUri);
|
|
4489
|
+
return;
|
|
4490
|
+
};
|
|
4491
|
+
var verifyAgainstAny = async (assertion, candidates) => {
|
|
4492
|
+
for (const jwk of candidates) {
|
|
4493
|
+
const verified = await verifyJwt(assertion, jwk);
|
|
4494
|
+
if (verified !== undefined)
|
|
4495
|
+
return verified;
|
|
4496
|
+
}
|
|
4497
|
+
return;
|
|
4498
|
+
};
|
|
4499
|
+
var verifyClientAssertion = async ({
|
|
4500
|
+
assertion,
|
|
4501
|
+
expectedAudience,
|
|
4502
|
+
jtiStore,
|
|
4503
|
+
resolveClient
|
|
4504
|
+
}) => {
|
|
4505
|
+
const [, payloadSegment] = assertion.split(".");
|
|
4506
|
+
if (payloadSegment === undefined)
|
|
4507
|
+
return;
|
|
4508
|
+
let payload;
|
|
4509
|
+
try {
|
|
4510
|
+
const parsed = JSON.parse(Buffer.from(payloadSegment, "base64url").toString("utf8"));
|
|
4511
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
4512
|
+
return;
|
|
4513
|
+
payload = parsed;
|
|
4514
|
+
} catch {
|
|
4515
|
+
return;
|
|
4516
|
+
}
|
|
4517
|
+
const {
|
|
4518
|
+
aud,
|
|
4519
|
+
exp,
|
|
4520
|
+
iss,
|
|
4521
|
+
jti,
|
|
4522
|
+
sub
|
|
4523
|
+
} = payload;
|
|
4524
|
+
if (typeof iss !== "string" || typeof sub !== "string" || iss !== sub || typeof exp !== "number") {
|
|
4525
|
+
return;
|
|
4526
|
+
}
|
|
4527
|
+
const audMatches = typeof aud === "string" && aud === expectedAudience || Array.isArray(aud) && aud.includes(expectedAudience);
|
|
4528
|
+
if (!audMatches)
|
|
4529
|
+
return;
|
|
4530
|
+
const expMs = exp * MILLISECONDS_IN_A_SECOND;
|
|
4531
|
+
const now = Date.now();
|
|
4532
|
+
if (expMs <= now || expMs - now > MAX_ASSERTION_LIFETIME_MS) {
|
|
4533
|
+
return;
|
|
4534
|
+
}
|
|
4535
|
+
const client = await resolveClient(iss);
|
|
4536
|
+
if (client === undefined)
|
|
4537
|
+
return;
|
|
4538
|
+
const candidates = await resolveClientJwks(client);
|
|
4539
|
+
if (candidates === undefined || candidates.length === 0)
|
|
4540
|
+
return;
|
|
4541
|
+
const verified = await verifyAgainstAny(assertion, candidates);
|
|
4542
|
+
if (verified === undefined)
|
|
4543
|
+
return;
|
|
4544
|
+
if (jtiStore !== undefined) {
|
|
4545
|
+
if (typeof jti !== "string")
|
|
4546
|
+
return;
|
|
4547
|
+
const fresh = await jtiStore.recordIfFresh(client.clientId, jti, expMs);
|
|
4548
|
+
if (!fresh)
|
|
4549
|
+
return;
|
|
4550
|
+
}
|
|
4551
|
+
return client;
|
|
4552
|
+
};
|
|
4553
|
+
|
|
4455
4554
|
// src/oidc/dpop.ts
|
|
4456
4555
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
4457
4556
|
var SECONDS_TO_MS = 1000;
|
|
@@ -4694,6 +4793,28 @@ var oidcProviderRoutes = (config) => {
|
|
|
4694
4793
|
const matches = await constantTimeEqual(await hashToken(clientSecret), client.hashedSecret);
|
|
4695
4794
|
return matches ? client : undefined;
|
|
4696
4795
|
};
|
|
4796
|
+
const authenticateTokenClient = async ({
|
|
4797
|
+
basicClientId,
|
|
4798
|
+
basicClientSecret,
|
|
4799
|
+
bodyClientAssertion,
|
|
4800
|
+
bodyClientAssertionType,
|
|
4801
|
+
bodyClientId,
|
|
4802
|
+
bodyClientSecret
|
|
4803
|
+
}) => {
|
|
4804
|
+
if (bodyClientAssertion !== undefined && bodyClientAssertionType === CLIENT_ASSERTION_TYPE) {
|
|
4805
|
+
return verifyClientAssertion({
|
|
4806
|
+
assertion: bodyClientAssertion,
|
|
4807
|
+
expectedAudience: tokenUrl,
|
|
4808
|
+
jtiStore: config.clientAssertionJtiStore,
|
|
4809
|
+
resolveClient: clientStore.findClient
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
const clientId = bodyClientId ?? basicClientId;
|
|
4813
|
+
const clientSecret = bodyClientSecret ?? basicClientSecret;
|
|
4814
|
+
if (clientId === undefined)
|
|
4815
|
+
return;
|
|
4816
|
+
return authenticateClient(clientId, clientSecret);
|
|
4817
|
+
};
|
|
4697
4818
|
const grantAuthorizationCode = async (client, body, dpop) => {
|
|
4698
4819
|
const {
|
|
4699
4820
|
code,
|
|
@@ -4842,8 +4963,10 @@ var oidcProviderRoutes = (config) => {
|
|
|
4842
4963
|
token_endpoint_auth_methods_supported: [
|
|
4843
4964
|
"client_secret_basic",
|
|
4844
4965
|
"client_secret_post",
|
|
4845
|
-
"none"
|
|
4846
|
-
|
|
4966
|
+
"none",
|
|
4967
|
+
"private_key_jwt"
|
|
4968
|
+
],
|
|
4969
|
+
token_endpoint_auth_signing_alg_values_supported: ["ES256"]
|
|
4847
4970
|
};
|
|
4848
4971
|
if (config.deviceAuthorizationStore) {
|
|
4849
4972
|
discovery.device_authorization_endpoint = `${issuer}${deviceAuthorizationRoute}`;
|
|
@@ -4968,12 +5091,14 @@ var oidcProviderRoutes = (config) => {
|
|
|
4968
5091
|
})
|
|
4969
5092
|
}).post(tokenRoute, async ({ body, headers }) => {
|
|
4970
5093
|
const basic = readBasicAuth2(headers.authorization);
|
|
4971
|
-
const
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
5094
|
+
const client = await authenticateTokenClient({
|
|
5095
|
+
basicClientId: basic.clientId,
|
|
5096
|
+
basicClientSecret: basic.clientSecret,
|
|
5097
|
+
bodyClientAssertion: body.client_assertion,
|
|
5098
|
+
bodyClientAssertionType: body.client_assertion_type,
|
|
5099
|
+
bodyClientId: body.client_id,
|
|
5100
|
+
bodyClientSecret: body.client_secret
|
|
5101
|
+
});
|
|
4977
5102
|
if (client === undefined) {
|
|
4978
5103
|
return oauthError2(HTTP_UNAUTHORIZED2, "invalid_client");
|
|
4979
5104
|
}
|
|
@@ -4993,6 +5118,8 @@ var oidcProviderRoutes = (config) => {
|
|
|
4993
5118
|
}, {
|
|
4994
5119
|
body: t12.Object({
|
|
4995
5120
|
audience: t12.Optional(t12.String()),
|
|
5121
|
+
client_assertion: t12.Optional(t12.String()),
|
|
5122
|
+
client_assertion_type: t12.Optional(t12.String()),
|
|
4996
5123
|
client_id: t12.Optional(t12.String()),
|
|
4997
5124
|
client_secret: t12.Optional(t12.String()),
|
|
4998
5125
|
code: t12.Optional(t12.String()),
|
|
@@ -20310,6 +20437,23 @@ var createInMemoryAuthorizationCodeStore = () => {
|
|
|
20310
20437
|
}
|
|
20311
20438
|
};
|
|
20312
20439
|
};
|
|
20440
|
+
var createInMemoryClientAssertionJtiStore = () => {
|
|
20441
|
+
const seen = new Map;
|
|
20442
|
+
return {
|
|
20443
|
+
recordIfFresh: async (clientId, jti, expiresAt) => {
|
|
20444
|
+
const now = Date.now();
|
|
20445
|
+
for (const [key, expiry] of seen) {
|
|
20446
|
+
if (expiry < now)
|
|
20447
|
+
seen.delete(key);
|
|
20448
|
+
}
|
|
20449
|
+
const composite = `${clientId}|${jti}`;
|
|
20450
|
+
if (seen.has(composite))
|
|
20451
|
+
return false;
|
|
20452
|
+
seen.set(composite, expiresAt);
|
|
20453
|
+
return true;
|
|
20454
|
+
}
|
|
20455
|
+
};
|
|
20456
|
+
};
|
|
20313
20457
|
var createInMemoryDeviceAuthorizationStore = () => {
|
|
20314
20458
|
const byDeviceCode = new Map;
|
|
20315
20459
|
return {
|
|
@@ -20384,12 +20528,22 @@ var createInMemoryOidcRefreshTokenStore = () => {
|
|
|
20384
20528
|
var URL_LENGTH = 2048;
|
|
20385
20529
|
var DEFAULT_LIST_LIMIT2 = 100;
|
|
20386
20530
|
var ID_LENGTH7 = 255;
|
|
20531
|
+
var oauthClientAssertionJtisTable = pgTable("auth_oauth_client_assertion_jtis", {
|
|
20532
|
+
client_id: varchar("client_id", { length: ID_LENGTH7 }).notNull(),
|
|
20533
|
+
composite_key: varchar("composite_key", {
|
|
20534
|
+
length: ID_LENGTH7
|
|
20535
|
+
}).primaryKey(),
|
|
20536
|
+
expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
|
|
20537
|
+
jti: varchar("jti", { length: ID_LENGTH7 }).notNull()
|
|
20538
|
+
});
|
|
20387
20539
|
var oauthClientsTable = pgTable("auth_oauth_clients", {
|
|
20388
20540
|
backchannel_logout_uri: varchar("backchannel_logout_uri", {
|
|
20389
20541
|
length: URL_LENGTH
|
|
20390
20542
|
}),
|
|
20391
20543
|
client_id: varchar("client_id", { length: ID_LENGTH7 }).primaryKey(),
|
|
20392
20544
|
hashed_secret: varchar("hashed_secret", { length: ID_LENGTH7 }),
|
|
20545
|
+
jwks_json: jsonb("jwks_json").$type(),
|
|
20546
|
+
jwks_uri: varchar("jwks_uri", { length: URL_LENGTH }),
|
|
20393
20547
|
name: varchar("name", { length: ID_LENGTH7 }).notNull(),
|
|
20394
20548
|
post_logout_redirect_uris: text("post_logout_redirect_uris").array(),
|
|
20395
20549
|
redirect_uris: text("redirect_uris").array().notNull(),
|
|
@@ -20446,6 +20600,8 @@ var toClient2 = (row) => ({
|
|
|
20446
20600
|
backchannelLogoutUri: row.backchannel_logout_uri ?? undefined,
|
|
20447
20601
|
clientId: row.client_id,
|
|
20448
20602
|
hashedSecret: row.hashed_secret ?? undefined,
|
|
20603
|
+
jwks: row.jwks_json ?? undefined,
|
|
20604
|
+
jwksUri: row.jwks_uri ?? undefined,
|
|
20449
20605
|
name: row.name,
|
|
20450
20606
|
postLogoutRedirectUris: row.post_logout_redirect_uris ?? undefined,
|
|
20451
20607
|
redirectUris: row.redirect_uris,
|
|
@@ -20520,6 +20676,7 @@ var toRefreshValues = (token) => ({
|
|
|
20520
20676
|
user_id: token.userId
|
|
20521
20677
|
});
|
|
20522
20678
|
var createNeonAuthorizationCodeStore = (databaseUrl) => createPostgresAuthorizationCodeStore(createNeonDatabase(databaseUrl));
|
|
20679
|
+
var createNeonClientAssertionJtiStore = (databaseUrl) => createPostgresClientAssertionJtiStore(createNeonDatabase(databaseUrl));
|
|
20523
20680
|
var createNeonDeviceAuthorizationStore = (databaseUrl) => createPostgresDeviceAuthorizationStore(createNeonDatabase(databaseUrl));
|
|
20524
20681
|
var createNeonLogoutDeliveryStore = (databaseUrl) => createPostgresLogoutDeliveryStore(createNeonDatabase(databaseUrl));
|
|
20525
20682
|
var createNeonOAuthClientStore = (databaseUrl) => createPostgresOAuthClientStore(createNeonDatabase(databaseUrl));
|
|
@@ -20533,6 +20690,23 @@ var createPostgresAuthorizationCodeStore = (db) => ({
|
|
|
20533
20690
|
await db.insert(oauthCodesTable).values(toCodeValues(code));
|
|
20534
20691
|
}
|
|
20535
20692
|
});
|
|
20693
|
+
var createPostgresClientAssertionJtiStore = (db) => ({
|
|
20694
|
+
recordIfFresh: async (clientId, jti, expiresAt) => {
|
|
20695
|
+
await db.delete(oauthClientAssertionJtisTable).where(lt(oauthClientAssertionJtisTable.expires_at_ms, Date.now()));
|
|
20696
|
+
const compositeKey = `${clientId}|${jti}`;
|
|
20697
|
+
try {
|
|
20698
|
+
await db.insert(oauthClientAssertionJtisTable).values({
|
|
20699
|
+
client_id: clientId,
|
|
20700
|
+
composite_key: compositeKey,
|
|
20701
|
+
expires_at_ms: expiresAt,
|
|
20702
|
+
jti
|
|
20703
|
+
});
|
|
20704
|
+
return true;
|
|
20705
|
+
} catch {
|
|
20706
|
+
return false;
|
|
20707
|
+
}
|
|
20708
|
+
}
|
|
20709
|
+
});
|
|
20536
20710
|
var createPostgresDeviceAuthorizationStore = (db) => ({
|
|
20537
20711
|
deleteByDeviceCodeHash: async (deviceCodeHash) => {
|
|
20538
20712
|
await db.delete(oauthDeviceAuthorizationsTable).where(eq(oauthDeviceAuthorizationsTable.device_code_hash, deviceCodeHash));
|
|
@@ -22033,6 +22207,7 @@ export {
|
|
|
22033
22207
|
verifyIdTokenHint,
|
|
22034
22208
|
verifyHcaptcha,
|
|
22035
22209
|
verifyDpopProof,
|
|
22210
|
+
verifyClientAssertion,
|
|
22036
22211
|
verifyAuditChain,
|
|
22037
22212
|
verifyApiKey,
|
|
22038
22213
|
verifyAccessToken,
|
|
@@ -22101,6 +22276,7 @@ export {
|
|
|
22101
22276
|
oauthDeviceAuthorizationsTable,
|
|
22102
22277
|
oauthCodesTable,
|
|
22103
22278
|
oauthClientsTable,
|
|
22279
|
+
oauthClientAssertionJtisTable,
|
|
22104
22280
|
mintLogoutToken,
|
|
22105
22281
|
mfaTotpRoutes,
|
|
22106
22282
|
mfaRoutes,
|
|
@@ -22208,6 +22384,7 @@ export {
|
|
|
22208
22384
|
createPostgresKnownDeviceStore,
|
|
22209
22385
|
createPostgresDeviceAuthorizationStore,
|
|
22210
22386
|
createPostgresCredentialStore,
|
|
22387
|
+
createPostgresClientAssertionJtiStore,
|
|
22211
22388
|
createPostgresAuthorizationCodeStore,
|
|
22212
22389
|
createPostgresAuditSink,
|
|
22213
22390
|
createPostgresApiKeyStore,
|
|
@@ -22237,6 +22414,7 @@ export {
|
|
|
22237
22414
|
createNeonDeviceAuthorizationStore,
|
|
22238
22415
|
createNeonDatabase,
|
|
22239
22416
|
createNeonCredentialStore,
|
|
22417
|
+
createNeonClientAssertionJtiStore,
|
|
22240
22418
|
createNeonAuthorizationCodeStore,
|
|
22241
22419
|
createNeonAuthSessionStore,
|
|
22242
22420
|
createNeonAuditSink,
|
|
@@ -22267,6 +22445,7 @@ export {
|
|
|
22267
22445
|
createInMemoryKnownDeviceStore,
|
|
22268
22446
|
createInMemoryDeviceAuthorizationStore,
|
|
22269
22447
|
createInMemoryCredentialStore,
|
|
22448
|
+
createInMemoryClientAssertionJtiStore,
|
|
22270
22449
|
createInMemoryCheckCache,
|
|
22271
22450
|
createInMemoryAuthorizationCodeStore,
|
|
22272
22451
|
createInMemoryAuthSessionStore,
|
|
@@ -22332,8 +22511,9 @@ export {
|
|
|
22332
22511
|
DEFAULT_INVITATION_TTL_MS,
|
|
22333
22512
|
DEFAULT_CREDENTIAL_SESSION_TTL_MS,
|
|
22334
22513
|
DEFAULT_BACKUP_CODE_COUNT,
|
|
22514
|
+
CLIENT_ASSERTION_TYPE,
|
|
22335
22515
|
AuthIdentityConflictError
|
|
22336
22516
|
};
|
|
22337
22517
|
|
|
22338
|
-
//# debugId=
|
|
22518
|
+
//# debugId=A9BAB004D30595D664756E2164756E21
|
|
22339
22519
|
//# sourceMappingURL=index.js.map
|