@absolutejs/auth 0.76.3 → 0.77.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.
@@ -1,4 +1,4 @@
1
- import { Elysia } from 'elysia';
1
+ import { Elysia, StatusMap, type ElysiaStatus } from 'elysia';
2
2
  import type { AuthSessionSource } from '../session/types';
3
3
  import { type AccessTokenPrincipalConfig, type AuthPrincipal } from '../principal';
4
4
  type AuthFailError = {
@@ -8,6 +8,11 @@ type AuthFailError = {
8
8
  readonly code: 'Unauthorized';
9
9
  readonly message: 'User is not authenticated';
10
10
  };
11
+ type AuthFailureResponse = ElysiaStatus<'Bad Request', 'Cookies are missing', (typeof StatusMap)['Bad Request']> | ElysiaStatus<'Unauthorized', 'User is not authenticated', (typeof StatusMap)['Unauthorized']>;
12
+ type ProtectRoute<UserType> = {
13
+ <AuthReturn, AuthFailReturn = never>(handleAuth: (user: UserType) => Promise<AuthReturn>, handleAuthFail?: (error: AuthFailError) => AuthFailReturn): Promise<AuthFailureResponse | AuthReturn | Awaited<AuthFailReturn>>;
14
+ <AuthReturn, AuthFailReturn = never>(handleAuth: (user: UserType) => AuthReturn, handleAuthFail?: (error: AuthFailError) => AuthFailReturn): Promise<AuthFailureResponse | AuthReturn | Awaited<AuthFailReturn>>;
15
+ };
11
16
  export declare const protectRoutePlugin: <UserType>({ accessTokens, authSessionStore }?: {
12
17
  accessTokens?: AccessTokenPrincipalConfig<UserType>;
13
18
  authSessionStore?: AuthSessionSource<UserType>;
@@ -18,8 +23,21 @@ export declare const protectRoutePlugin: <UserType>({ accessTokens, authSessionS
18
23
  unregisteredSession: import("..").UnregisteredSessionRecord;
19
24
  };
20
25
  derive: {
26
+ readonly absoluteAuthStatus: {
27
+ error: {
28
+ readonly code: "Bad Request";
29
+ readonly message: "Cookies are missing";
30
+ };
31
+ user: null;
32
+ impersonator?: undefined;
33
+ } | {
34
+ error: null;
35
+ impersonator: import("..").Impersonator | undefined;
36
+ user: NonNullable<UserType> | null;
37
+ };
21
38
  readonly authPrincipal: AuthPrincipal<UserType> | undefined;
22
- readonly protectRoute: <AuthReturn, AuthFailReturn = never>(handleAuth: (user: UserType) => AuthReturn | Promise<AuthReturn>, handleAuthFail?: (error: AuthFailError) => AuthFailReturn) => import("elysia").ElysiaStatus<"Unauthorized", "User is not authenticated", 401> | import("elysia").ElysiaStatus<"Bad Request", "Cookies are missing", 400> | AuthReturn | Promise<AuthReturn> | NonNullable<AuthFailReturn>;
39
+ } & {
40
+ readonly protectRoute: ProtectRoute<UserType>;
23
41
  };
24
42
  }, {
25
43
  typebox: {};
@@ -36,8 +54,7 @@ export declare const protectRoutePlugin: <UserType>({ accessTokens, authSessionS
36
54
  macroFn: {};
37
55
  parser: {};
38
56
  response: import("elysia/types").ExtractErrorFromHandle<{
39
- readonly authPrincipal: AuthPrincipal<UserType> | undefined;
40
- readonly protectRoute: <AuthReturn, AuthFailReturn = never>(handleAuth: (user: UserType) => AuthReturn | Promise<AuthReturn>, handleAuthFail?: (error: AuthFailError) => AuthFailReturn) => import("elysia").ElysiaStatus<"Unauthorized", "User is not authenticated", 401> | import("elysia").ElysiaStatus<"Bad Request", "Cookies are missing", 400> | AuthReturn | Promise<AuthReturn> | NonNullable<AuthFailReturn>;
57
+ readonly protectRoute: ProtectRoute<UserType>;
41
58
  }>;
42
59
  }, {}, import("elysia/types").DefaultEphemeral, import("elysia/types").DefaultEphemeral>;
43
60
  export {};
@@ -1,9 +1,14 @@
1
- import { Elysia } from 'elysia';
1
+ import { Elysia, StatusMap, type ElysiaStatus } from 'elysia';
2
2
  import type { AuthSessionSource } from '../session/types';
3
3
  type ReauthFailError = {
4
4
  readonly code: 'Unauthorized';
5
5
  readonly message: 'Recent authentication required';
6
6
  };
7
+ type ReauthFailureResponse = ElysiaStatus<'Unauthorized', 'Recent authentication required', (typeof StatusMap)['Unauthorized']>;
8
+ type RequireRecentAuth<UserType> = {
9
+ <AuthReturn, AuthFailReturn = never>(maxAgeMs: number, handleAuth: (user: UserType) => Promise<AuthReturn>, handleAuthFail?: (error: ReauthFailError) => AuthFailReturn): Promise<ReauthFailureResponse | AuthReturn | Awaited<AuthFailReturn>>;
10
+ <AuthReturn, AuthFailReturn = never>(maxAgeMs: number, handleAuth: (user: UserType) => AuthReturn, handleAuthFail?: (error: ReauthFailError) => AuthFailReturn): Promise<ReauthFailureResponse | AuthReturn | Awaited<AuthFailReturn>>;
11
+ };
7
12
  export declare const stepUpPlugin: <UserType>({ authSessionStore }?: {
8
13
  authSessionStore?: AuthSessionSource<UserType>;
9
14
  }) => Elysia<"", "local", {
@@ -13,7 +18,7 @@ export declare const stepUpPlugin: <UserType>({ authSessionStore }?: {
13
18
  unregisteredSession: import("..").UnregisteredSessionRecord;
14
19
  };
15
20
  derive: {
16
- readonly requireRecentAuth: <AuthReturn, AuthFailReturn>(maxAgeMs: number, handleAuth: (user: UserType) => AuthReturn | Promise<AuthReturn>, handleAuthFail?: (error: ReauthFailError) => AuthFailReturn) => Promise<AuthReturn | import("elysia").ElysiaStatus<"Unauthorized", "Recent authentication required", 401> | NonNullable<AuthFailReturn>>;
21
+ readonly requireRecentAuth: RequireRecentAuth<UserType>;
17
22
  };
18
23
  }, {
19
24
  typebox: {};
@@ -30,7 +35,7 @@ export declare const stepUpPlugin: <UserType>({ authSessionStore }?: {
30
35
  macroFn: {};
31
36
  parser: {};
32
37
  response: import("elysia/types").ExtractErrorFromHandle<{
33
- readonly requireRecentAuth: <AuthReturn, AuthFailReturn>(maxAgeMs: number, handleAuth: (user: UserType) => AuthReturn | Promise<AuthReturn>, handleAuthFail?: (error: ReauthFailError) => AuthFailReturn) => Promise<AuthReturn | import("elysia").ElysiaStatus<"Unauthorized", "Recent authentication required", 401> | NonNullable<AuthFailReturn>>;
38
+ readonly requireRecentAuth: RequireRecentAuth<UserType>;
34
39
  }>;
35
40
  }, {}, import("elysia/types").DefaultEphemeral, import("elysia/types").DefaultEphemeral>;
36
41
  export {};
package/dist/server.js CHANGED
@@ -4368,8 +4368,8 @@ var failureResponse = (config, failure, requiredScopes) => new Response(JSON.str
4368
4368
  var agentAuthContextPlugin = (config) => new Elysia2({
4369
4369
  name: "@absolutejs/auth/agent-context",
4370
4370
  seed: pluginDependencySeed(config)
4371
- }).derive(({ request }) => ({
4372
- protectAgent: async (requiredScopes, handleAuth, handleAuthFail) => {
4371
+ }).derive(({ request }) => {
4372
+ const protectAgent = async (requiredScopes, handleAuth, handleAuthFail) => {
4373
4373
  if (config === undefined) {
4374
4374
  const failure = {
4375
4375
  code: "Unauthorized",
@@ -4395,8 +4395,9 @@ var agentAuthContextPlugin = (config) => new Elysia2({
4395
4395
  return await handleAuthFail?.(failure) ?? failureResponse(config, failure, requiredScopes);
4396
4396
  }
4397
4397
  return handleAuth(principal);
4398
- }
4399
- })).as("global");
4398
+ };
4399
+ return { protectAgent };
4400
+ }).as("global");
4400
4401
 
4401
4402
  // src/agents/oauthGuide.ts
4402
4403
  var DEFAULT_GUIDE_ROUTE = "/auth.md";
@@ -5607,17 +5608,17 @@ var protectPermissionPlugin = ({
5607
5608
  }).use(sessionStore()).guard({
5608
5609
  cookie: t3.Cookie({ user_session_id: userSessionIdTypebox }),
5609
5610
  schema: "merge"
5610
- }).derive(({ store: { session }, cookie: { user_session_id }, status }) => ({
5611
- protectPermission: (check, handleAuth, handleAuthFail) => getStatusFromSource({
5611
+ }).derive(({ store: { session }, cookie: { user_session_id }, status }) => {
5612
+ const protectPermission = (check, handleAuth, handleAuthFail) => getStatusFromSource({
5612
5613
  authSessionStore,
5613
5614
  session,
5614
5615
  user_session_id
5615
5616
  }).then(async ({ user, error }) => {
5616
5617
  if (error) {
5617
- return handleAuthFail?.(error) ?? status(error.code, error.message);
5618
+ return await handleAuthFail?.(error) ?? status(error.code, error.message);
5618
5619
  }
5619
5620
  if (!user) {
5620
- return handleAuthFail?.({
5621
+ return await handleAuthFail?.({
5621
5622
  code: "Unauthorized",
5622
5623
  message: "User is not authenticated"
5623
5624
  }) ?? status("Unauthorized", "User is not authenticated");
@@ -5634,14 +5635,15 @@ var protectPermissionPlugin = ({
5634
5635
  organizationId: check.organizationId,
5635
5636
  type: "authorization_denied"
5636
5637
  });
5637
- return handleAuthFail?.({
5638
+ return await handleAuthFail?.({
5638
5639
  code: "Forbidden",
5639
5640
  message: "Insufficient permissions"
5640
5641
  }) ?? status("Forbidden", "Insufficient permissions");
5641
5642
  }
5642
5643
  return handleAuth(user);
5643
- })
5644
- })).as("global");
5644
+ });
5645
+ return { protectPermission };
5646
+ }).as("global");
5645
5647
 
5646
5648
  // src/routes/protectRoute.ts
5647
5649
  import { Elysia as Elysia6, t as t4 } from "elysia";
@@ -5705,8 +5707,7 @@ var protectRoutePlugin = ({
5705
5707
  }).derive(async ({
5706
5708
  store: { session },
5707
5709
  cookie: { user_session_id },
5708
- headers,
5709
- status
5710
+ headers
5710
5711
  }) => {
5711
5712
  const sessionStatus = await getStatusFromSource({
5712
5713
  authSessionStore,
@@ -5725,25 +5726,30 @@ var protectRoutePlugin = ({
5725
5726
  authorization: headers.authorization,
5726
5727
  config: accessTokens
5727
5728
  });
5728
- return {
5729
- authPrincipal,
5730
- protectRoute: (handleAuth, handleAuthFail) => {
5731
- const user = authPrincipal?.user;
5732
- const { error } = sessionStatus;
5733
- if (error) {
5734
- if (user)
5735
- return handleAuth(user);
5736
- return handleAuthFail?.(error) ?? status(error.code, error.message);
5737
- }
5738
- if (!user) {
5739
- return handleAuthFail?.({
5740
- code: "Unauthorized",
5741
- message: "User is not authenticated"
5742
- }) ?? status("Unauthorized", "User is not authenticated");
5743
- }
5744
- return handleAuth(user);
5729
+ return { absoluteAuthStatus: sessionStatus, authPrincipal };
5730
+ }).derive(({ absoluteAuthStatus, authPrincipal, status }) => {
5731
+ const protectRoute = async (handleAuth, handleAuthFail) => {
5732
+ if (!absoluteAuthStatus)
5733
+ return await handleAuthFail?.({
5734
+ code: "Unauthorized",
5735
+ message: "User is not authenticated"
5736
+ }) ?? status("Unauthorized", "User is not authenticated");
5737
+ const user = authPrincipal?.user;
5738
+ const { error } = absoluteAuthStatus;
5739
+ if (error) {
5740
+ if (user)
5741
+ return handleAuth(user);
5742
+ return await handleAuthFail?.(error) ?? status(error.code, error.message);
5745
5743
  }
5744
+ if (!user) {
5745
+ return await handleAuthFail?.({
5746
+ code: "Unauthorized",
5747
+ message: "User is not authenticated"
5748
+ }) ?? status("Unauthorized", "User is not authenticated");
5749
+ }
5750
+ return handleAuth(user);
5746
5751
  };
5752
+ return { protectRoute };
5747
5753
  }).as("global");
5748
5754
 
5749
5755
  // src/routes/stepUp.ts
@@ -5756,23 +5762,24 @@ var stepUpPlugin = ({
5756
5762
  }).use(sessionStore()).guard({
5757
5763
  cookie: t5.Cookie({ user_session_id: userSessionIdTypebox }),
5758
5764
  schema: "merge"
5759
- }).derive(({ store: { session }, cookie: { user_session_id }, status }) => ({
5760
- requireRecentAuth: (maxAgeMs, handleAuth, handleAuthFail) => loadSessionFromSource({
5765
+ }).derive(({ store: { session }, cookie: { user_session_id }, status }) => {
5766
+ const requireRecentAuth = (maxAgeMs, handleAuth, handleAuthFail) => loadSessionFromSource({
5761
5767
  authSessionStore,
5762
5768
  session,
5763
5769
  userSessionId: user_session_id.value
5764
- }).then((userSession) => {
5770
+ }).then(async (userSession) => {
5765
5771
  const authenticatedAt = userSession?.authenticatedAt;
5766
5772
  const isRecent = authenticatedAt !== undefined && Date.now() - authenticatedAt <= maxAgeMs;
5767
5773
  if (!userSession || !isRecent) {
5768
- return handleAuthFail?.({
5774
+ return await handleAuthFail?.({
5769
5775
  code: "Unauthorized",
5770
5776
  message: "Recent authentication required"
5771
5777
  }) ?? status("Unauthorized", "Recent authentication required");
5772
5778
  }
5773
5779
  return handleAuth(userSession.user);
5774
- })
5775
- })).as("global");
5780
+ });
5781
+ return { requireRecentAuth };
5782
+ }).as("global");
5776
5783
 
5777
5784
  // src/oidc/socketTickets.ts
5778
5785
  init_crypto();
@@ -8210,7 +8217,10 @@ var mfaTotpRoutes = ({
8210
8217
  verified: false
8211
8218
  };
8212
8219
  const factors = getMfaFactors(base).filter((existingFactor) => existingFactor.type !== "totp" || existingFactor.verified);
8213
- await mfaStore.saveEnrollment(withMfaFactors({ ...base, updatedAt: now }, [...factors, factor]));
8220
+ await mfaStore.saveEnrollment(withMfaFactors({ ...base, updatedAt: now }, [
8221
+ ...factors,
8222
+ factor
8223
+ ]));
8214
8224
  return status("OK", {
8215
8225
  factorId: factor.id,
8216
8226
  secret,
@@ -35018,17 +35028,17 @@ var resolveBindingFailureStatus = (binding, report) => {
35018
35028
  }
35019
35029
  return binding.status;
35020
35030
  };
35021
- var buildNextGrant = (grant, report, currentTime) => ({
35031
+ var buildNextGrant = (grant, report, currentTime, failurePolicy) => ({
35022
35032
  ...grant,
35023
35033
  lastRefreshError: report.message ?? report.code,
35024
35034
  metadata: annotateFailureMetadata(grant.metadata, report, currentTime),
35025
- status: resolveGrantFailureStatus(grant, report),
35035
+ status: failurePolicy === "record" ? grant.status : resolveGrantFailureStatus(grant, report),
35026
35036
  updatedAt: currentTime
35027
35037
  });
35028
- var buildNextBinding = (binding, report, currentTime) => ({
35038
+ var buildNextBinding = (binding, report, currentTime, failurePolicy) => ({
35029
35039
  ...binding,
35030
35040
  metadata: annotateFailureMetadata(binding.metadata, report, currentTime),
35031
- status: resolveBindingFailureStatus(binding, report),
35041
+ status: failurePolicy === "record" ? binding.status : resolveBindingFailureStatus(binding, report),
35032
35042
  updatedAt: currentTime
35033
35043
  });
35034
35044
  var resolveBindingCredential = async (grantStore, binding, input) => {
@@ -35045,6 +35055,7 @@ var resolveBindingCredential = async (grantStore, binding, input) => {
35045
35055
  var createLinkedProviderCredentialResolver = ({
35046
35056
  grantStore,
35047
35057
  bindingStore,
35058
+ failurePolicy = "latch",
35048
35059
  loadAccessTokenLease,
35049
35060
  refreshAccessTokenLease,
35050
35061
  now = () => Date.now(),
@@ -35090,10 +35101,10 @@ var createLinkedProviderCredentialResolver = ({
35090
35101
  const grant = await grantStore.getGrant(credential.grantId);
35091
35102
  const binding = await bindingStore.getBinding(credential.bindingId);
35092
35103
  if (grant) {
35093
- await grantStore.saveGrant(buildNextGrant(grant, report, currentTime));
35104
+ await grantStore.saveGrant(buildNextGrant(grant, report, currentTime, failurePolicy));
35094
35105
  }
35095
35106
  if (binding) {
35096
- await bindingStore.saveBinding(buildNextBinding(binding, report, currentTime));
35107
+ await bindingStore.saveBinding(buildNextBinding(binding, report, currentTime, failurePolicy));
35097
35108
  }
35098
35109
  await onReportFailure?.({
35099
35110
  binding: binding ?? undefined,
@@ -35392,7 +35403,7 @@ var toBinding2 = (row) => ({
35392
35403
  updatedAt: row.updated_at.getTime(),
35393
35404
  username: row.username ?? undefined
35394
35405
  });
35395
- var createNeonLinkedProviderBindingStore = (db) => ({
35406
+ var createLinkedProviderBindingStore = (db) => ({
35396
35407
  getBinding: async (id2) => {
35397
35408
  const [row] = await db.select().from(linkedProviderBindingsTable).where(eq(linkedProviderBindingsTable.id, id2)).limit(1);
35398
35409
  return row ? toBinding2(row) : undefined;
@@ -35443,7 +35454,7 @@ var createNeonLinkedProviderBindingStore = (db) => ({
35443
35454
  });
35444
35455
  }
35445
35456
  });
35446
- var createNeonLinkedProviderGrantStore = (db) => ({
35457
+ var createLinkedProviderGrantStore = (db) => ({
35447
35458
  getGrant: async (id2) => {
35448
35459
  const [row] = await db.select().from(linkedProviderGrantsTable).where(eq(linkedProviderGrantsTable.id, id2)).limit(1);
35449
35460
  return row ? toGrant2(row) : undefined;
@@ -35499,9 +35510,9 @@ var createNeonLinkedProviderStores = (databaseUrl) => {
35499
35510
  const sql2 = as(databaseUrl);
35500
35511
  const db = drizzle({ client: sql2 });
35501
35512
  return {
35502
- bindingStore: createNeonLinkedProviderBindingStore(db),
35513
+ bindingStore: createLinkedProviderBindingStore(db),
35503
35514
  db,
35504
- grantStore: createNeonLinkedProviderGrantStore(db)
35515
+ grantStore: createLinkedProviderGrantStore(db)
35505
35516
  };
35506
35517
  };
35507
35518
  var createNeonOAuthLinkedProviderCredentialResolver = async ({
@@ -40789,7 +40800,12 @@ var renderChunk = (chunk) => {
40789
40800
  return "";
40790
40801
  };
40791
40802
  var formatSqlTemplate = (value) => value.queryChunks.map(renderChunk).join("");
40792
- var formatDefault = (value) => {
40803
+ var columnSqlType = (column) => {
40804
+ const dimensions = Reflect.get(column, "dimensions");
40805
+ const elementType = column.getSQLType();
40806
+ return typeof dimensions === "number" && dimensions > 0 ? `${elementType}${"[]".repeat(dimensions)}` : elementType;
40807
+ };
40808
+ var formatScalarDefault = (value) => {
40793
40809
  if (value === null || value === undefined)
40794
40810
  return "NULL";
40795
40811
  if (is(value, SQL))
@@ -40800,15 +40816,17 @@ var formatDefault = (value) => {
40800
40816
  return value ? "true" : "false";
40801
40817
  if (typeof value === "number")
40802
40818
  return String(value);
40803
- if (Array.isArray(value) || typeof value === "object") {
40819
+ if (typeof value === "object") {
40804
40820
  return `'${JSON.stringify(value)}'::jsonb`;
40805
40821
  }
40806
40822
  return String(value);
40807
40823
  };
40808
- var columnSqlType = (column) => {
40824
+ var formatArrayDefault = (values) => `ARRAY[${values.map((value) => Array.isArray(value) ? formatArrayDefault(value) : formatScalarDefault(value)).join(", ")}]`;
40825
+ var formatDefault = (column, value) => {
40809
40826
  const dimensions = Reflect.get(column, "dimensions");
40810
- const elementType = column.getSQLType();
40811
- return typeof dimensions === "number" && dimensions > 0 ? `${elementType}${"[]".repeat(dimensions)}` : elementType;
40827
+ if (Array.isArray(value) && typeof dimensions === "number" && dimensions > 0)
40828
+ return `${formatArrayDefault(value)}::${columnSqlType(column)}`;
40829
+ return formatScalarDefault(value);
40812
40830
  };
40813
40831
  var columnSql = (column) => {
40814
40832
  const parts = [`"${column.name}"`, columnSqlType(column)];
@@ -40817,7 +40835,7 @@ var columnSql = (column) => {
40817
40835
  if (column.notNull && !column.primary)
40818
40836
  parts.push("NOT NULL");
40819
40837
  if (column.hasDefault && column.default !== undefined) {
40820
- parts.push(`DEFAULT ${formatDefault(column.default)}`);
40838
+ parts.push(`DEFAULT ${formatDefault(column, column.default)}`);
40821
40839
  }
40822
40840
  if (column.isUnique)
40823
40841
  parts.push("UNIQUE");
@@ -42067,5 +42085,5 @@ export {
42067
42085
  userSessionIdTypebox
42068
42086
  };
42069
42087
 
42070
- //# debugId=72D41A7F86EE7EF364756E2164756E21
42088
+ //# debugId=7D4E0B917AED1AD264756E2164756E21
42071
42089
  //# sourceMappingURL=server.js.map