@absolutejs/auth 0.28.0 → 0.29.0-beta.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/dist/index.js CHANGED
@@ -4496,6 +4496,138 @@ var verifyDpopProof = async ({
4496
4496
  return { jkt: await jwkThumbprint(header.jwk), jti };
4497
4497
  };
4498
4498
 
4499
+ // src/oidc/logout.ts
4500
+ var BACKCHANNEL_LOGOUT_EVENT = "http://schemas.openid.net/event/backchannel-logout";
4501
+ var buildLogoutClaims = ({
4502
+ clientId,
4503
+ issuer,
4504
+ now,
4505
+ sub
4506
+ }) => ({
4507
+ aud: clientId,
4508
+ events: { [BACKCHANNEL_LOGOUT_EVENT]: {} },
4509
+ iat: Math.floor(now / MILLISECONDS_IN_A_SECOND),
4510
+ iss: issuer,
4511
+ jti: crypto.randomUUID(),
4512
+ sub
4513
+ });
4514
+ var resolvePostLogoutRedirect = ({
4515
+ client,
4516
+ requestedUri
4517
+ }) => {
4518
+ if (requestedUri === undefined)
4519
+ return;
4520
+ const allow = client.postLogoutRedirectUris ?? [];
4521
+ return allow.includes(requestedUri) ? requestedUri : undefined;
4522
+ };
4523
+ var verifyIdTokenHint = async ({
4524
+ config,
4525
+ idTokenHint
4526
+ }) => {
4527
+ const verified = await verifyJwt(idTokenHint, config.signingKey.publicJwk);
4528
+ const payload = verified?.payload;
4529
+ if (payload === undefined || typeof payload.sub !== "string" || typeof payload.aud !== "string" || payload.iss !== config.issuer) {
4530
+ return;
4531
+ }
4532
+ return { audClientId: payload.aud, sub: payload.sub };
4533
+ };
4534
+ var BACKCHANNEL_TIMEOUT_SECONDS = 5;
4535
+ var DEFAULT_BACKCHANNEL_TIMEOUT_MS = BACKCHANNEL_TIMEOUT_SECONDS * MILLISECONDS_IN_A_SECOND;
4536
+ var errorMessage = (error) => error instanceof Error ? error.message : String(error);
4537
+ var statusFromError = (error) => {
4538
+ if (!(error instanceof Error))
4539
+ return;
4540
+ const match = /returned (\d+)/.exec(error.message);
4541
+ return match?.[1] === undefined ? undefined : Number(match[1]);
4542
+ };
4543
+ var mintLogoutToken = async ({
4544
+ clientId,
4545
+ config,
4546
+ now = Date.now(),
4547
+ sub
4548
+ }) => signJwt(buildLogoutClaims({ clientId, issuer: config.issuer, now, sub }), config.signingKey);
4549
+ var postLogoutToken = async ({
4550
+ endpointUrl,
4551
+ fetchImpl,
4552
+ logoutToken,
4553
+ timeoutMs
4554
+ }) => {
4555
+ const response = await fetchImpl(endpointUrl, {
4556
+ body: new URLSearchParams({ logout_token: logoutToken }).toString(),
4557
+ headers: {
4558
+ "content-type": "application/x-www-form-urlencoded"
4559
+ },
4560
+ method: "POST",
4561
+ signal: AbortSignal.timeout(timeoutMs)
4562
+ });
4563
+ if (!response.ok) {
4564
+ throw new Error(`Back-channel logout returned ${response.status}`);
4565
+ }
4566
+ };
4567
+ var deliverLogoutToOne = async ({
4568
+ clientId,
4569
+ config,
4570
+ endpointUrl,
4571
+ fetchImpl,
4572
+ logoutToken,
4573
+ onError,
4574
+ timeoutMs,
4575
+ userId
4576
+ }) => {
4577
+ try {
4578
+ await postLogoutToken({ endpointUrl, fetchImpl, logoutToken, timeoutMs });
4579
+ } catch (error) {
4580
+ const delivery = {
4581
+ attempts: 1,
4582
+ clientId,
4583
+ createdAt: Date.now(),
4584
+ endpointUrl,
4585
+ id: crypto.randomUUID(),
4586
+ lastError: errorMessage(error),
4587
+ lastStatus: statusFromError(error),
4588
+ logoutToken,
4589
+ userId
4590
+ };
4591
+ await config.logoutDeliveryStore?.recordFailure(delivery);
4592
+ await onError?.(delivery);
4593
+ }
4594
+ };
4595
+ var fanOutBackchannelLogout = async ({
4596
+ config,
4597
+ fetchImpl = globalThis.fetch,
4598
+ now = Date.now(),
4599
+ onError,
4600
+ skipClientId,
4601
+ timeoutMs = DEFAULT_BACKCHANNEL_TIMEOUT_MS,
4602
+ userId
4603
+ }) => {
4604
+ const clientIds = await config.refreshTokenStore.listClientIdsForUser(userId);
4605
+ const targets = await Promise.all(clientIds.filter((clientId) => clientId !== skipClientId).map(async (clientId) => {
4606
+ const client = await config.clientStore.findClient(clientId);
4607
+ return client?.backchannelLogoutUri === undefined ? undefined : { client, endpointUrl: client.backchannelLogoutUri };
4608
+ }));
4609
+ const reachable = targets.filter((target) => target !== undefined);
4610
+ await Promise.all(reachable.map(async ({ client, endpointUrl }) => {
4611
+ const logoutToken = await mintLogoutToken({
4612
+ clientId: client.clientId,
4613
+ config,
4614
+ now,
4615
+ sub: userId
4616
+ });
4617
+ await deliverLogoutToOne({
4618
+ clientId: client.clientId,
4619
+ config,
4620
+ endpointUrl,
4621
+ fetchImpl,
4622
+ logoutToken,
4623
+ onError,
4624
+ timeoutMs,
4625
+ userId
4626
+ });
4627
+ }));
4628
+ return reachable.map(({ client }) => client.clientId);
4629
+ };
4630
+
4499
4631
  // src/oidc/routes.ts
4500
4632
  var HTTP_OK2 = 200;
4501
4633
  var HTTP_BAD_REQUEST2 = 400;
@@ -4549,6 +4681,7 @@ var oidcProviderRoutes = (config) => {
4549
4681
  const revokeRoute = `${oidcRoute}/revoke`;
4550
4682
  const deviceAuthorizationRoute = `${oidcRoute}/device_authorization`;
4551
4683
  const deviceApproveRoute = `${oidcRoute}/device/decision`;
4684
+ const endSessionRoute = `${oidcRoute}/end_session`;
4552
4685
  const tokenUrl = `${issuer}${oidcRoute}/token`;
4553
4686
  const authenticateClient = async (clientId, clientSecret) => {
4554
4687
  const client = await clientStore.findClient(clientId);
@@ -4692,8 +4825,11 @@ var oidcProviderRoutes = (config) => {
4692
4825
  }
4693
4826
  const discovery = {
4694
4827
  authorization_endpoint: `${issuer}${authorizeRoute}`,
4828
+ backchannel_logout_session_supported: false,
4829
+ backchannel_logout_supported: true,
4695
4830
  code_challenge_methods_supported: ["S256"],
4696
4831
  dpop_signing_alg_values_supported: ["ES256"],
4832
+ end_session_endpoint: `${issuer}${endSessionRoute}`,
4697
4833
  grant_types_supported: grantTypes,
4698
4834
  id_token_signing_alg_values_supported: ["ES256"],
4699
4835
  introspection_endpoint: `${issuer}${introspectRoute}`,
@@ -4712,6 +4848,47 @@ var oidcProviderRoutes = (config) => {
4712
4848
  if (config.deviceAuthorizationStore) {
4713
4849
  discovery.device_authorization_endpoint = `${issuer}${deviceAuthorizationRoute}`;
4714
4850
  }
4851
+ const handleEndSession = async ({
4852
+ cookie,
4853
+ inMemorySession,
4854
+ query
4855
+ }) => {
4856
+ const hint = query.id_token_hint === undefined ? undefined : await verifyIdTokenHint({
4857
+ config,
4858
+ idTokenHint: query.id_token_hint
4859
+ });
4860
+ const clientId = hint?.audClientId ?? query.client_id;
4861
+ const client = clientId === undefined ? undefined : await config.clientStore.findClient(clientId);
4862
+ const userSession = await loadSessionFromSource({
4863
+ authSessionStore,
4864
+ session: inMemorySession,
4865
+ userSessionId: cookie.value
4866
+ });
4867
+ const resolvedSub = hint?.sub ?? (userSession === undefined ? undefined : getUserId(userSession.user));
4868
+ await clearSession({
4869
+ authSessionStore,
4870
+ cookie,
4871
+ inMemorySession
4872
+ });
4873
+ if (resolvedSub !== undefined) {
4874
+ await fanOutBackchannelLogout({
4875
+ config,
4876
+ skipClientId: clientId,
4877
+ userId: resolvedSub
4878
+ });
4879
+ }
4880
+ const redirectUri = client === undefined ? undefined : resolvePostLogoutRedirect({
4881
+ client,
4882
+ requestedUri: query.post_logout_redirect_uri
4883
+ });
4884
+ if (redirectUri === undefined) {
4885
+ return jsonResponse({ ok: true }, HTTP_OK2);
4886
+ }
4887
+ const url = new URL(redirectUri);
4888
+ if (query.state !== undefined)
4889
+ url.searchParams.set("state", query.state);
4890
+ return redirectTo(url.toString());
4891
+ };
4715
4892
  return new Elysia15().use(sessionStore()).get(authorizeRoute, async ({ cookie: { user_session_id }, query, request, store }) => {
4716
4893
  const {
4717
4894
  client_id: clientId,
@@ -4944,6 +5121,42 @@ var oidcProviderRoutes = (config) => {
4944
5121
  cookie: t12.Cookie({
4945
5122
  user_session_id: t12.Optional(userSessionIdTypebox)
4946
5123
  })
5124
+ }).get(endSessionRoute, async ({
5125
+ cookie: { user_session_id },
5126
+ query,
5127
+ store
5128
+ }) => handleEndSession({
5129
+ cookie: user_session_id,
5130
+ inMemorySession: store.session,
5131
+ query
5132
+ }), {
5133
+ cookie: t12.Cookie({
5134
+ user_session_id: t12.Optional(userSessionIdTypebox)
5135
+ }),
5136
+ query: t12.Object({
5137
+ client_id: t12.Optional(t12.String()),
5138
+ id_token_hint: t12.Optional(t12.String()),
5139
+ post_logout_redirect_uri: t12.Optional(t12.String()),
5140
+ state: t12.Optional(t12.String())
5141
+ })
5142
+ }).post(endSessionRoute, async ({
5143
+ body,
5144
+ cookie: { user_session_id },
5145
+ store
5146
+ }) => handleEndSession({
5147
+ cookie: user_session_id,
5148
+ inMemorySession: store.session,
5149
+ query: body
5150
+ }), {
5151
+ body: t12.Object({
5152
+ client_id: t12.Optional(t12.String()),
5153
+ id_token_hint: t12.Optional(t12.String()),
5154
+ post_logout_redirect_uri: t12.Optional(t12.String()),
5155
+ state: t12.Optional(t12.String())
5156
+ }),
5157
+ cookie: t12.Cookie({
5158
+ user_session_id: t12.Optional(userSessionIdTypebox)
5159
+ })
4947
5160
  }).get(jwksRoute, () => ({ keys: [toPublicJwk(signingKey)] })).get("/.well-known/openid-configuration", () => discovery);
4948
5161
  };
4949
5162
 
@@ -7920,6 +8133,14 @@ var webauthnRoutes = ({
7920
8133
 
7921
8134
  // src/webhooks/config.ts
7922
8135
  var DEFAULT_TIMEOUT_SECONDS = 5;
8136
+ var DEFAULT_RETRY_ATTEMPTS = 3;
8137
+ var DEFAULT_RETRY_INITIAL_DELAY_MS = MILLISECONDS_IN_A_SECOND;
8138
+ var DEFAULT_RETRY_BACKOFF_MULTIPLIER = 2;
8139
+ var DEFAULT_WEBHOOK_RETRY = {
8140
+ attempts: DEFAULT_RETRY_ATTEMPTS,
8141
+ backoffMultiplier: DEFAULT_RETRY_BACKOFF_MULTIPLIER,
8142
+ initialDelayMs: DEFAULT_RETRY_INITIAL_DELAY_MS
8143
+ };
7923
8144
  var DEFAULT_WEBHOOK_TIMEOUT_MS = MILLISECONDS_IN_A_SECOND * DEFAULT_TIMEOUT_SECONDS;
7924
8145
 
7925
8146
  // src/webhooks/sign.ts
@@ -7952,12 +8173,145 @@ var verifyWebhookSignature = async ({
7952
8173
  };
7953
8174
 
7954
8175
  // src/webhooks/dispatcher.ts
8176
+ var defaultSleep = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));
8177
+ var attemptOnce = async ({
8178
+ envelope,
8179
+ endpoint,
8180
+ fetchImpl,
8181
+ payload,
8182
+ signature,
8183
+ timeoutMs,
8184
+ timestamp
8185
+ }) => {
8186
+ const response = await fetchImpl(endpoint.url, {
8187
+ body: payload,
8188
+ headers: {
8189
+ "content-type": "application/json",
8190
+ "webhook-id": envelope.id,
8191
+ "webhook-signature": signature,
8192
+ "webhook-timestamp": timestamp
8193
+ },
8194
+ method: "POST",
8195
+ signal: AbortSignal.timeout(timeoutMs)
8196
+ });
8197
+ if (!response.ok) {
8198
+ throw new Error(`Webhook delivery returned ${response.status}`);
8199
+ }
8200
+ return response.status;
8201
+ };
8202
+ var errorMessage2 = (error) => error instanceof Error ? error.message : String(error);
8203
+ var statusFromError2 = (error) => {
8204
+ if (!(error instanceof Error))
8205
+ return;
8206
+ const match = /returned (\d+)/.exec(error.message);
8207
+ return match?.[1] === undefined ? undefined : Number(match[1]);
8208
+ };
8209
+ var persistFailure = async ({
8210
+ attempts,
8211
+ deliveryStore,
8212
+ endpoint,
8213
+ envelope,
8214
+ lastError
8215
+ }) => {
8216
+ if (deliveryStore === undefined)
8217
+ return;
8218
+ const record = {
8219
+ attempts,
8220
+ createdAt: Date.now(),
8221
+ endpointUrl: endpoint.url,
8222
+ envelope,
8223
+ lastError: errorMessage2(lastError),
8224
+ lastStatus: statusFromError2(lastError)
8225
+ };
8226
+ await deliveryStore.recordFailure(record);
8227
+ };
8228
+ var tryDeliverThenBackoff = async ({
8229
+ attempt,
8230
+ endpoint,
8231
+ envelope,
8232
+ fetchImpl,
8233
+ payload,
8234
+ retry,
8235
+ signature,
8236
+ sleep,
8237
+ timeoutMs,
8238
+ timestamp
8239
+ }) => {
8240
+ try {
8241
+ await attemptOnce({
8242
+ endpoint,
8243
+ envelope,
8244
+ fetchImpl,
8245
+ payload,
8246
+ signature,
8247
+ timeoutMs,
8248
+ timestamp
8249
+ });
8250
+ return;
8251
+ } catch (error) {
8252
+ const isLastAttempt = attempt >= retry.attempts - 1;
8253
+ await (isLastAttempt ? Promise.resolve() : sleep(retry.initialDelayMs * retry.backoffMultiplier ** attempt));
8254
+ return error;
8255
+ }
8256
+ };
8257
+ var deliverToEndpoint = async ({
8258
+ deliveryStore,
8259
+ endpoint,
8260
+ envelope,
8261
+ fetchImpl,
8262
+ onDeliveryError,
8263
+ payload,
8264
+ retry,
8265
+ signature,
8266
+ sleep,
8267
+ timeoutMs,
8268
+ timestamp
8269
+ }) => {
8270
+ let lastError;
8271
+ for (let attempt = 0;attempt < retry.attempts; attempt++) {
8272
+ const error = await tryDeliverThenBackoff({
8273
+ attempt,
8274
+ endpoint,
8275
+ envelope,
8276
+ fetchImpl,
8277
+ payload,
8278
+ retry,
8279
+ signature,
8280
+ sleep,
8281
+ timeoutMs,
8282
+ timestamp
8283
+ });
8284
+ if (error === undefined)
8285
+ return;
8286
+ lastError = error;
8287
+ }
8288
+ await onDeliveryError?.({
8289
+ endpoint,
8290
+ error: lastError,
8291
+ event: envelope
8292
+ });
8293
+ await persistFailure({
8294
+ attempts: retry.attempts,
8295
+ deliveryStore,
8296
+ endpoint,
8297
+ envelope,
8298
+ lastError
8299
+ });
8300
+ };
7955
8301
  var createWebhookDispatcher = ({
8302
+ deliveryStore,
7956
8303
  endpoints,
7957
8304
  fetch: fetchImpl = globalThis.fetch,
7958
8305
  onDeliveryError,
8306
+ retry,
8307
+ sleep = defaultSleep,
7959
8308
  timeoutMs = DEFAULT_WEBHOOK_TIMEOUT_MS
7960
8309
  }) => {
8310
+ const effectiveRetry = {
8311
+ attempts: retry?.attempts ?? DEFAULT_WEBHOOK_RETRY.attempts,
8312
+ backoffMultiplier: retry?.backoffMultiplier ?? DEFAULT_WEBHOOK_RETRY.backoffMultiplier,
8313
+ initialDelayMs: retry?.initialDelayMs ?? DEFAULT_WEBHOOK_RETRY.initialDelayMs
8314
+ };
7961
8315
  const dispatch = async (event) => {
7962
8316
  const envelope = {
7963
8317
  createdAt: Date.now(),
@@ -7967,35 +8321,26 @@ var createWebhookDispatcher = ({
7967
8321
  };
7968
8322
  const payload = JSON.stringify(envelope);
7969
8323
  const timestamp = Math.floor(Date.now() / MILLISECONDS_IN_A_SECOND).toString();
7970
- await Promise.all(endpoints.map(async (endpoint) => {
7971
- try {
7972
- const signature = await signWebhook({
7973
- id: envelope.id,
7974
- payload,
7975
- secret: endpoint.secret,
7976
- timestamp
7977
- });
7978
- const response = await fetchImpl(endpoint.url, {
7979
- body: payload,
7980
- headers: {
7981
- "content-type": "application/json",
7982
- "webhook-id": envelope.id,
7983
- "webhook-signature": signature,
7984
- "webhook-timestamp": timestamp
7985
- },
7986
- method: "POST",
7987
- signal: AbortSignal.timeout(timeoutMs)
7988
- });
7989
- if (!response.ok) {
7990
- throw new Error(`Webhook delivery returned ${response.status}`);
7991
- }
7992
- } catch (error) {
7993
- await onDeliveryError?.({
7994
- endpoint,
7995
- error,
7996
- event: envelope
7997
- });
7998
- }
8324
+ await Promise.all(endpoints.filter((endpoint) => endpoint.events === undefined || endpoint.events.includes(event.type)).map(async (endpoint) => {
8325
+ const signature = await signWebhook({
8326
+ id: envelope.id,
8327
+ payload,
8328
+ secret: endpoint.secret,
8329
+ timestamp
8330
+ });
8331
+ await deliverToEndpoint({
8332
+ deliveryStore,
8333
+ endpoint,
8334
+ envelope,
8335
+ fetchImpl,
8336
+ onDeliveryError,
8337
+ payload,
8338
+ retry: effectiveRetry,
8339
+ signature,
8340
+ sleep,
8341
+ timeoutMs,
8342
+ timestamp
8343
+ });
7999
8344
  }));
8000
8345
  };
8001
8346
  return dispatch;
@@ -19951,6 +20296,7 @@ var createPostgresApiKeyStore = (db) => ({
19951
20296
  }
19952
20297
  });
19953
20298
  // src/oidc/inMemoryStores.ts
20299
+ var DEFAULT_LIST_LIMIT = 100;
19954
20300
  var createInMemoryAuthorizationCodeStore = () => {
19955
20301
  const codes = new Map;
19956
20302
  return {
@@ -19991,6 +20337,18 @@ var createInMemoryDeviceAuthorizationStore = () => {
19991
20337
  }
19992
20338
  };
19993
20339
  };
20340
+ var createInMemoryLogoutDeliveryStore = () => {
20341
+ const failures = new Map;
20342
+ return {
20343
+ listFailed: async (limit = DEFAULT_LIST_LIMIT) => Array.from(failures.values()).sort((left, right) => right.createdAt - left.createdAt).slice(0, limit),
20344
+ recordFailure: async (delivery) => {
20345
+ failures.set(delivery.id, delivery);
20346
+ },
20347
+ removeFailure: async (deliveryId) => {
20348
+ failures.delete(deliveryId);
20349
+ }
20350
+ };
20351
+ };
19994
20352
  var createInMemoryOAuthClientStore = (clients) => {
19995
20353
  const registry = new Map(clients.map((client) => [client.clientId, client]));
19996
20354
  return {
@@ -20012,17 +20370,28 @@ var createInMemoryOidcRefreshTokenStore = () => {
20012
20370
  }
20013
20371
  },
20014
20372
  getToken: async (tokenHash) => tokens.get(tokenHash),
20373
+ listClientIdsForUser: async (userId) => {
20374
+ const now = Date.now();
20375
+ const active = Array.from(tokens.values()).filter((token) => token.userId === userId && token.expiresAt > now);
20376
+ return Array.from(new Set(active.map((token) => token.clientId)));
20377
+ },
20015
20378
  saveToken: async (token) => {
20016
20379
  tokens.set(token.tokenHash, { ...token });
20017
20380
  }
20018
20381
  };
20019
20382
  };
20020
20383
  // src/oidc/postgresStores.ts
20384
+ var URL_LENGTH = 2048;
20385
+ var DEFAULT_LIST_LIMIT2 = 100;
20021
20386
  var ID_LENGTH7 = 255;
20022
20387
  var oauthClientsTable = pgTable("auth_oauth_clients", {
20388
+ backchannel_logout_uri: varchar("backchannel_logout_uri", {
20389
+ length: URL_LENGTH
20390
+ }),
20023
20391
  client_id: varchar("client_id", { length: ID_LENGTH7 }).primaryKey(),
20024
20392
  hashed_secret: varchar("hashed_secret", { length: ID_LENGTH7 }),
20025
20393
  name: varchar("name", { length: ID_LENGTH7 }).notNull(),
20394
+ post_logout_redirect_uris: text("post_logout_redirect_uris").array(),
20026
20395
  redirect_uris: text("redirect_uris").array().notNull(),
20027
20396
  scopes: text("scopes").array().notNull()
20028
20397
  });
@@ -20052,6 +20421,17 @@ var oauthDeviceAuthorizationsTable = pgTable("auth_oauth_device_authorizations",
20052
20421
  user_code: varchar("user_code", { length: 16 }).notNull().unique(),
20053
20422
  user_sub: varchar("user_sub", { length: ID_LENGTH7 })
20054
20423
  });
20424
+ var oauthLogoutDeliveriesTable = pgTable("auth_oauth_logout_deliveries", {
20425
+ attempts: bigint("attempts", { mode: "number" }).notNull(),
20426
+ client_id: varchar("client_id", { length: ID_LENGTH7 }).notNull(),
20427
+ created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
20428
+ endpoint_url: varchar("endpoint_url", { length: URL_LENGTH }).notNull(),
20429
+ id: varchar("id", { length: ID_LENGTH7 }).primaryKey(),
20430
+ last_error: text("last_error"),
20431
+ last_status: bigint("last_status", { mode: "number" }),
20432
+ logout_token: text("logout_token").notNull(),
20433
+ user_id: varchar("user_id", { length: ID_LENGTH7 }).notNull()
20434
+ });
20055
20435
  var oauthRefreshTokensTable = pgTable("auth_oauth_refresh_tokens", {
20056
20436
  claims_json: jsonb("claims_json").$type(),
20057
20437
  client_id: varchar("client_id", { length: ID_LENGTH7 }).notNull(),
@@ -20063,12 +20443,25 @@ var oauthRefreshTokensTable = pgTable("auth_oauth_refresh_tokens", {
20063
20443
  user_id: varchar("user_id", { length: ID_LENGTH7 }).notNull()
20064
20444
  });
20065
20445
  var toClient2 = (row) => ({
20446
+ backchannelLogoutUri: row.backchannel_logout_uri ?? undefined,
20066
20447
  clientId: row.client_id,
20067
20448
  hashedSecret: row.hashed_secret ?? undefined,
20068
20449
  name: row.name,
20450
+ postLogoutRedirectUris: row.post_logout_redirect_uris ?? undefined,
20069
20451
  redirectUris: row.redirect_uris,
20070
20452
  scopes: row.scopes
20071
20453
  });
20454
+ var toLogoutDelivery = (row) => ({
20455
+ attempts: row.attempts,
20456
+ clientId: row.client_id,
20457
+ createdAt: row.created_at_ms,
20458
+ endpointUrl: row.endpoint_url,
20459
+ id: row.id,
20460
+ lastError: row.last_error ?? undefined,
20461
+ lastStatus: row.last_status ?? undefined,
20462
+ logoutToken: row.logout_token,
20463
+ userId: row.user_id
20464
+ });
20072
20465
  var toCode = (row) => ({
20073
20466
  claims: row.claims_json ?? undefined,
20074
20467
  clientId: row.client_id,
@@ -20128,6 +20521,7 @@ var toRefreshValues = (token) => ({
20128
20521
  });
20129
20522
  var createNeonAuthorizationCodeStore = (databaseUrl) => createPostgresAuthorizationCodeStore(createNeonDatabase(databaseUrl));
20130
20523
  var createNeonDeviceAuthorizationStore = (databaseUrl) => createPostgresDeviceAuthorizationStore(createNeonDatabase(databaseUrl));
20524
+ var createNeonLogoutDeliveryStore = (databaseUrl) => createPostgresLogoutDeliveryStore(createNeonDatabase(databaseUrl));
20131
20525
  var createNeonOAuthClientStore = (databaseUrl) => createPostgresOAuthClientStore(createNeonDatabase(databaseUrl));
20132
20526
  var createNeonOidcRefreshTokenStore = (databaseUrl) => createPostgresOidcRefreshTokenStore(createNeonDatabase(databaseUrl));
20133
20527
  var createPostgresAuthorizationCodeStore = (db) => ({
@@ -20168,6 +20562,28 @@ var createPostgresDeviceAuthorizationStore = (db) => ({
20168
20562
  await db.update(oauthDeviceAuthorizationsTable).set({ status, user_sub: userSub ?? null }).where(eq(oauthDeviceAuthorizationsTable.device_code_hash, deviceCodeHash));
20169
20563
  }
20170
20564
  });
20565
+ var createPostgresLogoutDeliveryStore = (db) => ({
20566
+ listFailed: async (limit = DEFAULT_LIST_LIMIT2) => {
20567
+ const rows = await db.select().from(oauthLogoutDeliveriesTable).orderBy(desc(oauthLogoutDeliveriesTable.created_at_ms)).limit(limit);
20568
+ return rows.map(toLogoutDelivery);
20569
+ },
20570
+ recordFailure: async (delivery) => {
20571
+ await db.insert(oauthLogoutDeliveriesTable).values({
20572
+ attempts: delivery.attempts,
20573
+ client_id: delivery.clientId,
20574
+ created_at_ms: delivery.createdAt,
20575
+ endpoint_url: delivery.endpointUrl,
20576
+ id: delivery.id,
20577
+ last_error: delivery.lastError ?? null,
20578
+ last_status: delivery.lastStatus ?? null,
20579
+ logout_token: delivery.logoutToken,
20580
+ user_id: delivery.userId
20581
+ });
20582
+ },
20583
+ removeFailure: async (deliveryId) => {
20584
+ await db.delete(oauthLogoutDeliveriesTable).where(eq(oauthLogoutDeliveriesTable.id, deliveryId));
20585
+ }
20586
+ });
20171
20587
  var createPostgresOAuthClientStore = (db) => ({
20172
20588
  findClient: async (clientId) => {
20173
20589
  const [row] = await db.select().from(oauthClientsTable).where(eq(oauthClientsTable.client_id, clientId)).limit(1);
@@ -20186,6 +20602,10 @@ var createPostgresOidcRefreshTokenStore = (db) => ({
20186
20602
  const [row] = await db.select().from(oauthRefreshTokensTable).where(eq(oauthRefreshTokensTable.token_hash, tokenHash)).limit(1);
20187
20603
  return row ? toRefresh(row) : undefined;
20188
20604
  },
20605
+ listClientIdsForUser: async (userId) => {
20606
+ const rows = await db.selectDistinct({ client_id: oauthRefreshTokensTable.client_id }).from(oauthRefreshTokensTable).where(and(eq(oauthRefreshTokensTable.user_id, userId), gt(oauthRefreshTokensTable.expires_at_ms, Date.now())));
20607
+ return rows.map((row) => row.client_id);
20608
+ },
20189
20609
  saveToken: async (token) => {
20190
20610
  await db.insert(oauthRefreshTokensTable).values(toRefreshValues(token));
20191
20611
  }
@@ -21318,6 +21738,62 @@ var createPostgresPasswordlessTokenStore = (db) => ({
21318
21738
  });
21319
21739
  }
21320
21740
  });
21741
+ // src/webhooks/inMemoryStore.ts
21742
+ var DEFAULT_LIST_LIMIT3 = 100;
21743
+ var createInMemoryWebhookDeliveryStore = () => {
21744
+ const failures = new Map;
21745
+ return {
21746
+ listFailed: async (limit = DEFAULT_LIST_LIMIT3) => Array.from(failures.values()).sort((left, right) => right.createdAt - left.createdAt).slice(0, limit),
21747
+ recordFailure: async (delivery) => {
21748
+ failures.set(delivery.envelope.id, delivery);
21749
+ },
21750
+ removeFailure: async (envelopeId) => {
21751
+ failures.delete(envelopeId);
21752
+ }
21753
+ };
21754
+ };
21755
+ // src/webhooks/postgresStore.ts
21756
+ var ID_LENGTH15 = 255;
21757
+ var URL_LENGTH2 = 2048;
21758
+ var DEFAULT_LIST_LIMIT4 = 100;
21759
+ var webhookDeliveriesTable = pgTable("auth_webhook_deliveries", {
21760
+ attempts: bigint("attempts", { mode: "number" }).notNull(),
21761
+ created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
21762
+ endpoint_url: varchar("endpoint_url", { length: URL_LENGTH2 }).notNull(),
21763
+ envelope_id: varchar("envelope_id", { length: ID_LENGTH15 }).primaryKey(),
21764
+ envelope_json: jsonb("envelope_json").$type().notNull(),
21765
+ last_error: text("last_error"),
21766
+ last_status: bigint("last_status", { mode: "number" })
21767
+ });
21768
+ var toDelivery = (row) => ({
21769
+ attempts: row.attempts,
21770
+ createdAt: row.created_at_ms,
21771
+ endpointUrl: row.endpoint_url,
21772
+ envelope: row.envelope_json,
21773
+ lastError: row.last_error ?? undefined,
21774
+ lastStatus: row.last_status ?? undefined
21775
+ });
21776
+ var createNeonWebhookDeliveryStore = (databaseUrl) => createPostgresWebhookDeliveryStore(createNeonDatabase(databaseUrl));
21777
+ var createPostgresWebhookDeliveryStore = (db) => ({
21778
+ listFailed: async (limit = DEFAULT_LIST_LIMIT4) => {
21779
+ const rows = await db.select().from(webhookDeliveriesTable).orderBy(desc(webhookDeliveriesTable.created_at_ms)).limit(limit);
21780
+ return rows.map(toDelivery);
21781
+ },
21782
+ recordFailure: async (delivery) => {
21783
+ await db.insert(webhookDeliveriesTable).values({
21784
+ attempts: delivery.attempts,
21785
+ created_at_ms: delivery.createdAt,
21786
+ endpoint_url: delivery.endpointUrl,
21787
+ envelope_id: delivery.envelope.id,
21788
+ envelope_json: delivery.envelope,
21789
+ last_error: delivery.lastError ?? null,
21790
+ last_status: delivery.lastStatus ?? null
21791
+ });
21792
+ },
21793
+ removeFailure: async (envelopeId) => {
21794
+ await db.delete(webhookDeliveriesTable).where(eq(webhookDeliveriesTable.envelope_id, envelopeId));
21795
+ }
21796
+ });
21321
21797
  // src/portal/inMemorySetupSessionStore.ts
21322
21798
  var cloneSession = (value) => ({
21323
21799
  ...value,
@@ -21339,19 +21815,19 @@ var createInMemorySetupSessionStore = () => {
21339
21815
  };
21340
21816
  };
21341
21817
  // src/portal/postgresSetupSessionStore.ts
21342
- var ID_LENGTH15 = 255;
21818
+ var ID_LENGTH16 = 255;
21343
21819
  var setupSessionsTable = pgTable("auth_setup_sessions", {
21344
21820
  capabilities: jsonb("capabilities").$type().notNull().default([]),
21345
21821
  created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
21346
- created_by: varchar("created_by", { length: ID_LENGTH15 }),
21822
+ created_by: varchar("created_by", { length: ID_LENGTH16 }),
21347
21823
  expires_at_ms: bigint("expires_at_ms", { mode: "number" }).notNull(),
21348
21824
  organization_id: varchar("organization_id", {
21349
- length: ID_LENGTH15
21825
+ length: ID_LENGTH16
21350
21826
  }).notNull(),
21351
21827
  setup_session_id: varchar("setup_session_id", {
21352
- length: ID_LENGTH15
21828
+ length: ID_LENGTH16
21353
21829
  }).primaryKey(),
21354
- token_hash: varchar("token_hash", { length: ID_LENGTH15 }).notNull().unique()
21830
+ token_hash: varchar("token_hash", { length: ID_LENGTH16 }).notNull().unique()
21355
21831
  });
21356
21832
  var toSession = (row) => ({
21357
21833
  capabilities: row.capabilities,
@@ -21542,6 +22018,7 @@ var auth = async ({
21542
22018
  };
21543
22019
  export {
21544
22020
  writeWarrant,
22021
+ webhookDeliveriesTable,
21545
22022
  webauthnRoutes,
21546
22023
  webauthnCredentialsTable,
21547
22024
  warrantsTable,
@@ -21553,6 +22030,7 @@ export {
21553
22030
  verifyPkce,
21554
22031
  verifyPassword,
21555
22032
  verifyJwt,
22033
+ verifyIdTokenHint,
21556
22034
  verifyHcaptcha,
21557
22035
  verifyDpopProof,
21558
22036
  verifyAuditChain,
@@ -21591,6 +22069,7 @@ export {
21591
22069
  resolveSetupSession,
21592
22070
  resolveScimOrganization,
21593
22071
  resolveProviderClientConfiguration,
22072
+ resolvePostLogoutRedirect,
21594
22073
  resolvePermissions,
21595
22074
  resolveOAuthTokenExpiresAt,
21596
22075
  resolveOAuthAuthorization,
@@ -21618,9 +22097,11 @@ export {
21618
22097
  oidcProviderRoutes,
21619
22098
  oidcProviderOptions,
21620
22099
  oauthRefreshTokensTable,
22100
+ oauthLogoutDeliveriesTable,
21621
22101
  oauthDeviceAuthorizationsTable,
21622
22102
  oauthCodesTable,
21623
22103
  oauthClientsTable,
22104
+ mintLogoutToken,
21624
22105
  mfaTotpRoutes,
21625
22106
  mfaRoutes,
21626
22107
  mfaEnrollmentsTable,
@@ -21669,6 +22150,7 @@ export {
21669
22150
  generateEncryptionKey,
21670
22151
  generateBackupCodes,
21671
22152
  fingerprintDevice,
22153
+ fanOutBackchannelLogout,
21672
22154
  extractPropFromIdentity,
21673
22155
  exportAuditCsv,
21674
22156
  exchangeToken,
@@ -21707,6 +22189,7 @@ export {
21707
22189
  createRiskEngine,
21708
22190
  createRedisLockoutStore,
21709
22191
  createRedisAuthSessionStore,
22192
+ createPostgresWebhookDeliveryStore,
21710
22193
  createPostgresWebAuthnCredentialStore,
21711
22194
  createPostgresWarrantStore,
21712
22195
  createPostgresVaultStore,
@@ -21719,6 +22202,7 @@ export {
21719
22202
  createPostgresOidcRefreshTokenStore,
21720
22203
  createPostgresOAuthClientStore,
21721
22204
  createPostgresMfaStore,
22205
+ createPostgresLogoutDeliveryStore,
21722
22206
  createPostgresLoginHistoryStore,
21723
22207
  createPostgresLockoutStore,
21724
22208
  createPostgresKnownDeviceStore,
@@ -21731,6 +22215,7 @@ export {
21731
22215
  createPostgresAccessTokenStore,
21732
22216
  createOrganization,
21733
22217
  createOAuthLinkedProviderCredentialResolver,
22218
+ createNeonWebhookDeliveryStore,
21734
22219
  createNeonWebAuthnCredentialStore,
21735
22220
  createNeonWarrantStore,
21736
22221
  createNeonVaultStore,
@@ -21744,6 +22229,7 @@ export {
21744
22229
  createNeonOAuthLinkedProviderCredentialResolver,
21745
22230
  createNeonOAuthClientStore,
21746
22231
  createNeonMfaStore,
22232
+ createNeonLogoutDeliveryStore,
21747
22233
  createNeonLoginHistoryStore,
21748
22234
  createNeonLockoutStore,
21749
22235
  createNeonLinkedProviderStores,
@@ -21761,6 +22247,7 @@ export {
21761
22247
  createMembershipPermissionResolver,
21762
22248
  createLockoutGuard,
21763
22249
  createLinkedProviderCredentialResolver,
22250
+ createInMemoryWebhookDeliveryStore,
21764
22251
  createInMemoryWebAuthnCredentialStore,
21765
22252
  createInMemoryWarrantStore,
21766
22253
  createInMemoryVaultStore,
@@ -21773,6 +22260,7 @@ export {
21773
22260
  createInMemoryOidcRefreshTokenStore,
21774
22261
  createInMemoryOAuthClientStore,
21775
22262
  createInMemoryMfaStore,
22263
+ createInMemoryLogoutDeliveryStore,
21776
22264
  createInMemoryLoginHistoryStore,
21777
22265
  createInMemoryLockoutStore,
21778
22266
  createInMemoryLinkedProviderStores,
@@ -21818,6 +22306,7 @@ export {
21818
22306
  acceptInvitation,
21819
22307
  WEBAUTHN_CHALLENGE_COOKIE,
21820
22308
  DEFAULT_WEBHOOK_TIMEOUT_MS,
22309
+ DEFAULT_WEBHOOK_RETRY,
21821
22310
  DEFAULT_WEBAUTHN_SESSION_TTL_MS,
21822
22311
  DEFAULT_WEBAUTHN_ROUTE,
21823
22312
  DEFAULT_WEBAUTHN_CHALLENGE_TTL_MS,
@@ -21846,5 +22335,5 @@ export {
21846
22335
  AuthIdentityConflictError
21847
22336
  };
21848
22337
 
21849
- //# debugId=E246ECC6A14E235864756E2164756E21
22338
+ //# debugId=9518CC46948D590564756E2164756E21
21850
22339
  //# sourceMappingURL=index.js.map