@absolutejs/auth 0.57.9 → 0.59.0

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.
Files changed (63) hide show
  1. package/README.md +38 -0
  2. package/dist/cli/migrate.js +31 -12
  3. package/dist/cli/migrate.js.map +4 -4
  4. package/dist/index.js +522 -95
  5. package/dist/index.js.map +17 -15
  6. package/dist/manifest.js +8 -1
  7. package/dist/manifest.js.map +3 -3
  8. package/dist/mfa/challenge.d.ts +5 -3
  9. package/dist/mfa/config.d.ts +9 -0
  10. package/dist/mfa/management.d.ts +3 -3
  11. package/dist/mfa/postgresMfaStore.d.ts +60 -0
  12. package/dist/mfa/recentAuth.d.ts +2 -0
  13. package/dist/mfa/routes.d.ts +15 -10
  14. package/dist/mfa/sms.d.ts +45 -7
  15. package/dist/mfa/totp.d.ts +3 -3
  16. package/dist/mfa/types.d.ts +35 -0
  17. package/dist/server.js +521 -96
  18. package/dist/server.js.map +18 -16
  19. package/dist/types.d.ts +5 -1
  20. package/dist/verification/types.d.ts +58 -0
  21. package/package.json +1 -1
  22. package/dist/agents/index.d.ts +0 -13
  23. package/dist/cli/import/auth0.d.ts +0 -2
  24. package/dist/cli/import/clerk.d.ts +0 -2
  25. package/dist/cli/import/index.d.ts +0 -10
  26. package/dist/cli/import/lucia.d.ts +0 -2
  27. package/dist/cli/import/nextauth.d.ts +0 -2
  28. package/dist/cli/import/supabase.d.ts +0 -2
  29. package/dist/cli/import/types.d.ts +0 -27
  30. package/dist/cli/migrate.d.ts +0 -2
  31. package/dist/client/components/react/SignIn.d.ts +0 -32
  32. package/dist/client/components/react/SignUp.d.ts +0 -29
  33. package/dist/client/components/react/UserButton.d.ts +0 -36
  34. package/dist/client/createAuthClient.d.ts +0 -285
  35. package/dist/client/index.d.ts +0 -3
  36. package/dist/client/passkeyHelpers.d.ts +0 -19
  37. package/dist/client/react.d.ts +0 -87
  38. package/dist/client/sessionExpiry.d.ts +0 -37
  39. package/dist/client/solid.d.ts +0 -86
  40. package/dist/client/svelte.d.ts +0 -86
  41. package/dist/client/vue.d.ts +0 -88
  42. package/dist/fingerprint-client/index.d.ts +0 -26
  43. package/dist/htmx/index.d.ts +0 -2
  44. package/dist/index.d.ts +0 -3637
  45. package/dist/linkedProviders/index.d.ts +0 -3
  46. package/dist/manifest.d.ts +0 -18
  47. package/dist/manifest.json +0 -364
  48. package/dist/oidc/index.d.ts +0 -12
  49. package/dist/oidc/operator.d.ts +0 -14
  50. package/dist/plugins/denyDisposableEmail.d.ts +0 -7
  51. package/dist/plugins/discordAlert.d.ts +0 -7
  52. package/dist/plugins/geoBlock.d.ts +0 -8
  53. package/dist/plugins/index.d.ts +0 -12
  54. package/dist/plugins/pagerdutyAlert.d.ts +0 -9
  55. package/dist/plugins/posthogIdentify.d.ts +0 -7
  56. package/dist/plugins/slackAlert.d.ts +0 -7
  57. package/dist/providers/index.d.ts +0 -2
  58. package/dist/saml.d.ts +0 -1
  59. package/dist/server.d.ts +0 -31
  60. package/dist/sso/nodeSamlAdapter.d.ts +0 -8
  61. package/dist/vault/index.d.ts +0 -5
  62. package/dist/webauthn/simpleWebAuthnAdapter.d.ts +0 -3
  63. package/dist/webauthn.d.ts +0 -1
package/README.md CHANGED
@@ -89,6 +89,44 @@ The concrete SimpleWebAuthn adapter follows the same boundary:
89
89
  import { createSimpleWebAuthnAdapter } from '@absolutejs/auth/webauthn';
90
90
  ```
91
91
 
92
+ ### Provider-managed phone verification
93
+
94
+ `verificationProvider` is the vendor-neutral phone-verification lifecycle.
95
+ The contract supports SMS, WhatsApp, and voice-call OTP; MFA currently selects
96
+ SMS while signup, recovery, phone change, and step-up flows can use the same
97
+ provider contract. Auth owns enrollment, atomic resend/code-consumption policy,
98
+ audit, and session promotion; the provider generates, delivers, checks, and
99
+ cancels the code.
100
+
101
+ ```ts
102
+ import { auth } from '@absolutejs/auth/server';
103
+ import { createTwilioVerificationProvider } from '@absolutejs/auth-twilio';
104
+ import { Twilio } from 'twilio';
105
+
106
+ const authPlugin = await auth({
107
+ // credentials, mfa, stores, providersConfiguration, etc.
108
+ verificationProvider: createTwilioVerificationProvider({
109
+ client: new Twilio(
110
+ process.env.TWILIO_ACCOUNT_SID!,
111
+ process.env.TWILIO_AUTH_TOKEN!
112
+ ),
113
+ verifyServiceSid: process.env.TWILIO_VERIFY_SERVICE_SID!,
114
+ serviceTokenTtlMs: 10 * 60 * 1000
115
+ })
116
+ });
117
+ ```
118
+
119
+ Without a provider, `mfa.onSendSmsCode` keeps codes local and accepts any
120
+ application-owned delivery system such as `@absolutejs/dispatch`. Its payload
121
+ includes `purpose` and `userId` for safe templates, audit correlation, and
122
+ tenant routing. Provider and local-code sends share the default 30-second
123
+ per-enrollment resend cooldown; configure `mfa.smsResendCooldownMs` when needed.
124
+ MFA enrollment, replacement, and removal require a fresh authentication by
125
+ default (five minutes); configure `mfa.managementAuthMaxAgeMs` deliberately.
126
+
127
+ Production databases must run the `mfa` migration block after upgrading to add
128
+ the atomic SMS challenge identifier.
129
+
92
130
  ### Delegated AI agents
93
131
 
94
132
  The `agentAuth` block provides a standards-first agent identity layer. It
@@ -2672,7 +2672,7 @@ var lockoutsTable = pgTable8("auth_lockouts", {
2672
2672
  });
2673
2673
 
2674
2674
  // src/mfa/postgresMfaStore.ts
2675
- import { eq as eq9 } from "drizzle-orm";
2675
+ import { and as and4, eq as eq9, isNull as isNull2, lte, or as or2, sql } from "drizzle-orm";
2676
2676
  import {
2677
2677
  bigint as bigint7,
2678
2678
  boolean as boolean3,
@@ -2688,12 +2688,16 @@ var mfaEnrollmentsTable = pgTable9("auth_mfa_enrollments", {
2688
2688
  backup_code_hashes: jsonb3("backup_code_hashes").$type().notNull().default([]),
2689
2689
  created_at_ms: bigint7("created_at_ms", { mode: "number" }).notNull(),
2690
2690
  last_used_at_ms: bigint7("last_used_at_ms", { mode: "number" }),
2691
+ sms_challenge_id: text4("sms_challenge_id"),
2692
+ sms_code_sent_at_ms: bigint7("sms_code_sent_at_ms", { mode: "number" }),
2691
2693
  sms_failed_attempts: smallint("sms_failed_attempts").notNull().default(0),
2692
2694
  sms_pending_code_expires_at_ms: bigint7("sms_pending_code_expires_at_ms", {
2693
2695
  mode: "number"
2694
2696
  }),
2695
2697
  sms_pending_code_hash: text4("sms_pending_code_hash"),
2698
+ sms_pending_purpose: text4("sms_pending_purpose").$type(),
2696
2699
  sms_phone: varchar9("sms_phone", { length: PHONE_LENGTH }),
2700
+ sms_provider_reference: text4("sms_provider_reference"),
2697
2701
  sms_verified: boolean3("sms_verified").notNull().default(false),
2698
2702
  totp_failed_attempts: smallint("totp_failed_attempts").notNull().default(0),
2699
2703
  totp_secret_ciphertext: text4("totp_secret_ciphertext"),
@@ -2703,7 +2707,7 @@ var mfaEnrollmentsTable = pgTable9("auth_mfa_enrollments", {
2703
2707
  });
2704
2708
 
2705
2709
  // src/oidc/postgresStores.ts
2706
- import { and as and4, desc as desc6, eq as eq10, gt as gt2, lt as lt3 } from "drizzle-orm";
2710
+ import { and as and5, desc as desc6, eq as eq10, gt as gt2, lt as lt3 } from "drizzle-orm";
2707
2711
  import {
2708
2712
  bigint as bigint8,
2709
2713
  boolean as boolean4,
@@ -2833,7 +2837,7 @@ var oauthRefreshTokensTable = pgTable10("auth_oauth_refresh_tokens", {
2833
2837
  });
2834
2838
 
2835
2839
  // src/organizations/postgresOrganizationStore.ts
2836
- import { and as and5, desc as desc7, eq as eq11 } from "drizzle-orm";
2840
+ import { and as and6, desc as desc7, eq as eq11 } from "drizzle-orm";
2837
2841
  import {
2838
2842
  bigint as bigint9,
2839
2843
  jsonb as jsonb5,
@@ -2909,7 +2913,7 @@ var setupSessionsTable = pgTable13("auth_setup_sessions", {
2909
2913
  });
2910
2914
 
2911
2915
  // src/roles/postgresRoleStore.ts
2912
- import { and as and6, eq as eq14 } from "drizzle-orm";
2916
+ import { and as and7, eq as eq14 } from "drizzle-orm";
2913
2917
  import {
2914
2918
  bigint as bigint12,
2915
2919
  jsonb as jsonb7,
@@ -2995,7 +2999,7 @@ var samlServiceProvidersTable = pgTable17("auth_saml_service_providers", {
2995
2999
  });
2996
3000
 
2997
3001
  // src/sso/postgresSsoConnectionStore.ts
2998
- import { and as and7, desc as desc9, eq as eq18 } from "drizzle-orm";
3002
+ import { and as and8, desc as desc9, eq as eq18 } from "drizzle-orm";
2999
3003
  import { bigint as bigint16, boolean as boolean5, jsonb as jsonb9, pgTable as pgTable18, varchar as varchar18 } from "drizzle-orm/pg-core";
3000
3004
  var ID_LENGTH15 = 255;
3001
3005
  var TYPE_LENGTH2 = 16;
@@ -3045,7 +3049,7 @@ var vcPresentationRequestsTable = pgTable19("auth_vc_presentation_requests", {
3045
3049
  });
3046
3050
 
3047
3051
  // src/vault/postgresVaultStore.ts
3048
- import { and as and8, eq as eq20 } from "drizzle-orm";
3052
+ import { and as and9, eq as eq20 } from "drizzle-orm";
3049
3053
  import {
3050
3054
  bigint as bigint18,
3051
3055
  pgTable as pgTable20,
@@ -3170,18 +3174,18 @@ var JOURNAL_DDL = `CREATE TABLE IF NOT EXISTS "auth_migrations" (
3170
3174
  var isJournalRow = (value) => typeof value === "object" && value !== null && typeof Reflect.get(value, "id") === "string";
3171
3175
  var isBlockName = (value) => Object.hasOwn(blockMigrations, value);
3172
3176
  var allBlockNames = () => Object.keys(blockMigrations).filter(isBlockName);
3173
- var applyOne = async (client, id, sql, log) => {
3174
- await client.query(sql);
3177
+ var applyOne = async (client, id, sql2, log) => {
3178
+ await client.query(sql2);
3175
3179
  await client.query(`INSERT INTO "auth_migrations" ("id", "applied_at_ms") VALUES ($1, $2)`, [id, Date.now()]);
3176
3180
  log(`apply ${id}`);
3177
3181
  };
3178
- var runOne = async (client, id, sql, applied, result, log) => {
3182
+ var runOne = async (client, id, sql2, applied, result, log) => {
3179
3183
  if (applied.has(id)) {
3180
3184
  result.skipped.push(id);
3181
3185
  log(`skip ${id}`);
3182
3186
  return;
3183
3187
  }
3184
- await applyOne(client, id, sql, log);
3188
+ await applyOne(client, id, sql2, log);
3185
3189
  result.applied.push(id);
3186
3190
  };
3187
3191
  var runMigrations = async ({
@@ -3240,6 +3244,19 @@ var mfaTotpLockoutMigration = {
3240
3244
  id: "0003_totp_lockout",
3241
3245
  sql: 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "totp_failed_attempts" smallint NOT NULL DEFAULT 0;'
3242
3246
  };
3247
+ var mfaSmsDeliveryPolicyMigration = {
3248
+ id: "0004_sms_delivery_policy",
3249
+ sql: [
3250
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_code_sent_at_ms" bigint;',
3251
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_pending_purpose" text;',
3252
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_provider_reference" text;'
3253
+ ].join(`
3254
+ `)
3255
+ };
3256
+ var mfaSmsAtomicChallengeMigration = {
3257
+ id: "0005_sms_atomic_challenge",
3258
+ sql: 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_challenge_id" text;'
3259
+ };
3243
3260
  var oidcResourceAudienceMigration = {
3244
3261
  id: "0002_resource_audience",
3245
3262
  sql: [
@@ -3294,7 +3311,9 @@ var blockMigrations = {
3294
3311
  migrations: [
3295
3312
  ...initMigration("mfa", [mfaEnrollmentsTable]).migrations,
3296
3313
  mfaSmsColumnsMigration,
3297
- mfaTotpLockoutMigration
3314
+ mfaTotpLockoutMigration,
3315
+ mfaSmsDeliveryPolicyMigration,
3316
+ mfaSmsAtomicChallengeMigration
3298
3317
  ]
3299
3318
  },
3300
3319
  oidc: {
@@ -3531,5 +3550,5 @@ var main = async () => {
3531
3550
  };
3532
3551
  await main();
3533
3552
 
3534
- //# debugId=CF3F65D5B7AF923D64756E2164756E21
3553
+ //# debugId=F3F4FD6B1C5A081764756E2164756E21
3535
3554
  //# sourceMappingURL=migrate.js.map