@meistrari/auth-core 1.20.1 → 1.22.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.
package/dist/index.mjs CHANGED
@@ -2,13 +2,75 @@ import { decodeJwt, createRemoteJWKSet, jwtVerify } from 'jose';
2
2
  import { apiKeyClient } from '@better-auth/api-key/client';
3
3
  import { ssoClient } from '@better-auth/sso/client';
4
4
  import { createAuthClient } from 'better-auth/client';
5
- import { organizationClient, inferOrgAdditionalFields, twoFactorClient, jwtClient, adminClient, inferAdditionalFields } from 'better-auth/client/plugins';
5
+ import { organizationClient, inferOrgAdditionalFields, twoFactorClient, jwtClient, adminClient, inferAdditionalFields, emailOTPClient } from 'better-auth/client/plugins';
6
6
  import { createAccessControl } from 'better-auth/plugins/access';
7
7
  import { defaultStatements } from 'better-auth/plugins/organization/access';
8
- import z$1, { z } from 'zod';
8
+ import z, { z as z$1 } from 'zod';
9
9
  export { APIError } from 'better-auth';
10
10
 
11
- const version = "1.20.1";
11
+ const version = "1.22.0";
12
+
13
+ function parsedEnumValues(schema) {
14
+ return Object.fromEntries(
15
+ Object.entries(schema.enum).map(([key, value]) => [
16
+ key,
17
+ schema.parse(value)
18
+ ])
19
+ );
20
+ }
21
+
22
+ const AMRBrand = Symbol("amr");
23
+ const AALBrand = Symbol("aal");
24
+ const ACRBrand = Symbol("acr");
25
+ const AuthMethodBrand = Symbol("authMethod");
26
+ const AMR = z.enum({
27
+ Pwd: "pwd",
28
+ Otp: "otp",
29
+ Oauth: "oauth",
30
+ Sso: "sso",
31
+ Saml: "saml"
32
+ }).brand(AMRBrand);
33
+ const AAL = z.enum({
34
+ Aal1: "aal1",
35
+ Aal2: "aal2",
36
+ Aal3: "aal3"
37
+ }).brand(AALBrand);
38
+ const ACR = z.enum({
39
+ Unspecified: "urn:tela:auth:unspecified"
40
+ }).brand(ACRBrand);
41
+ const AuthMethod = z.enum({
42
+ Password: "password",
43
+ EmailOTP: "email_otp",
44
+ OAuth: "oauth",
45
+ SAML: "saml",
46
+ Unknown: "unknown"
47
+ }).brand(AuthMethodBrand);
48
+ const AMRs = parsedEnumValues(AMR);
49
+ const AALs = parsedEnumValues(AAL);
50
+ const ACRs = parsedEnumValues(ACR);
51
+ const AuthMethods = parsedEnumValues(AuthMethod);
52
+ const assuranceFields = {
53
+ authMethod: {
54
+ type: "string",
55
+ required: true
56
+ },
57
+ amr: {
58
+ type: "json",
59
+ required: true
60
+ },
61
+ aal: {
62
+ type: "string",
63
+ required: true
64
+ },
65
+ acr: {
66
+ type: "string",
67
+ required: true
68
+ },
69
+ assuredAt: {
70
+ type: "date",
71
+ required: true
72
+ }
73
+ };
12
74
 
13
75
  const statements = {
14
76
  ...defaultStatements,
@@ -68,21 +130,36 @@ const invitationAdditionalFields = {
68
130
  required: false
69
131
  }
70
132
  };
71
- const JWTPayloadUser = z.object({
72
- id: z.string(),
73
- name: z.string(),
74
- image: z.string().nullable().optional(),
75
- role: z.string().nullable()
133
+ const JWTPayloadUser = z$1.object({
134
+ id: z$1.string(),
135
+ name: z$1.string(),
136
+ image: z$1.string().nullable().optional(),
137
+ role: z$1.string().nullable()
138
+ });
139
+ const JWTPayloadWorkspace = z$1.object({
140
+ id: z$1.string(),
141
+ title: z$1.string()
76
142
  });
77
- const JWTPayloadWorkspace = z.object({
78
- id: z.string(),
79
- title: z.string()
143
+ const JWTPayloadAssurance = z$1.object({
144
+ authMethod: AuthMethod,
145
+ amr: AMR.array(),
146
+ aal: AAL,
147
+ acr: ACR,
148
+ assuredAt: z$1.string().datetime()
80
149
  });
81
- const JWTPayload = z.object({
82
- email: z.string(),
150
+ const DEFAULT_JWT_ASSURANCE = {
151
+ authMethod: AuthMethods.Unknown,
152
+ amr: [],
153
+ aal: AALs.Aal1,
154
+ acr: ACRs.Unspecified,
155
+ assuredAt: (/* @__PURE__ */ new Date(0)).toISOString()
156
+ };
157
+ const JWTPayload = z$1.object({
158
+ email: z$1.string(),
83
159
  user: JWTPayloadUser,
84
160
  workspace: JWTPayloadWorkspace,
85
- sessionKey: z.string()
161
+ sessionKey: z$1.string(),
162
+ assurance: JWTPayloadAssurance.optional().default(DEFAULT_JWT_ASSURANCE)
86
163
  });
87
164
 
88
165
  const DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
@@ -227,6 +304,34 @@ function applicationsPluginClient() {
227
304
  };
228
305
  }
229
306
 
307
+ function sessionAssurancePluginClient() {
308
+ return {
309
+ id: "session-assurance",
310
+ getActions: ($fetch) => ({
311
+ sessionAssurance: {
312
+ getSessionAssurance: async () => {
313
+ return await $fetch("/session-assurance");
314
+ },
315
+ stepUpWithPassword: async (body) => {
316
+ return await $fetch("/session-assurance/step-up/password", { method: "POST", body });
317
+ },
318
+ sendOtp: async () => {
319
+ return await $fetch("/session-assurance/step-up/otp/send", { method: "POST" });
320
+ },
321
+ verifyOtp: async (body) => {
322
+ return await $fetch("/session-assurance/step-up/otp/verify", { method: "POST", body });
323
+ },
324
+ beginOAuthStepUp: async (body) => {
325
+ return await $fetch("/session-assurance/step-up/oauth/begin", { method: "POST", body });
326
+ },
327
+ completeOAuthStepUp: async (body) => {
328
+ return await $fetch("/session-assurance/step-up/oauth/complete", { method: "POST", body });
329
+ }
330
+ }
331
+ })
332
+ };
333
+ }
334
+
230
335
  function customEndpointsPluginClient() {
231
336
  return {
232
337
  id: "custom-endpoints",
@@ -263,7 +368,9 @@ function createAPIClient(apiUrl, fetchOptions = {}) {
263
368
  inferAdditionalFields({
264
369
  user: userAdditionalFields
265
370
  }),
266
- applicationsPluginClient()
371
+ applicationsPluginClient(),
372
+ sessionAssurancePluginClient(),
373
+ emailOTPClient()
267
374
  ],
268
375
  fetchOptions: {
269
376
  ...fetchOptions,
@@ -277,6 +384,127 @@ function createAPIClient(apiUrl, fetchOptions = {}) {
277
384
  });
278
385
  }
279
386
 
387
+ class AdminService {
388
+ /**
389
+ * Creates a new AdminService instance.
390
+ *
391
+ * @param client - The API client for making admin requests
392
+ */
393
+ constructor(client) {
394
+ this.client = client;
395
+ }
396
+ /**
397
+ * Lists all organizations, optionally with member and application previews
398
+ * and totals when a preview size is requested.
399
+ *
400
+ * @param options - Pagination, ordering, search, and preview options
401
+ * @returns The paginated organization listing
402
+ */
403
+ async listOrganizations(options = {}) {
404
+ return await this.client.$fetch("/admin/organizations", {
405
+ method: "GET",
406
+ query: {
407
+ ...options.limit !== void 0 ? { limit: options.limit } : {},
408
+ ...options.offset !== void 0 ? { offset: options.offset } : {},
409
+ ...options.sortBy ? { sortBy: options.sortBy } : {},
410
+ ...options.sortDirection ? { sortDirection: options.sortDirection } : {},
411
+ ...options.query ? { query: options.query } : {},
412
+ ...options.membersPreview !== void 0 ? { members_preview: options.membersPreview } : {},
413
+ ...options.applicationsPreview !== void 0 ? { applications_preview: options.applicationsPreview } : {}
414
+ }
415
+ });
416
+ }
417
+ /**
418
+ * Lists all Better Auth users from the user table.
419
+ *
420
+ * @param options - Pagination, search, filter, and ordering options
421
+ * @returns The paginated user listing
422
+ */
423
+ async listUsers(options = {}) {
424
+ return await this.client.$fetch("/admin/list-users", {
425
+ method: "GET",
426
+ query: {
427
+ ...options.limit !== void 0 ? { limit: options.limit } : {},
428
+ ...options.offset !== void 0 ? { offset: options.offset } : {},
429
+ ...options.searchValue ? { searchValue: options.searchValue } : {},
430
+ ...options.searchField ? { searchField: options.searchField } : {},
431
+ ...options.searchOperator ? { searchOperator: options.searchOperator } : {},
432
+ ...options.sortBy ? { sortBy: options.sortBy } : {},
433
+ ...options.sortDirection ? { sortDirection: options.sortDirection } : {},
434
+ ...options.filterField ? { filterField: options.filterField } : {},
435
+ ...options.filterValue !== void 0 ? { filterValue: options.filterValue } : {},
436
+ ...options.filterOperator ? { filterOperator: options.filterOperator } : {}
437
+ }
438
+ });
439
+ }
440
+ /**
441
+ * Fetches a single organization, optionally with adjacent IDs in
442
+ * the listing defined by the ordering options.
443
+ *
444
+ * @param options - Organization ID and listing adjacency options
445
+ * @returns The organization
446
+ */
447
+ async getOrganization(options) {
448
+ const { data } = await this.client.$fetch(`/admin/organizations/${encodeURIComponent(options.organizationId)}`, {
449
+ method: "GET",
450
+ query: {
451
+ ...options.sortBy ? { sortBy: options.sortBy } : {},
452
+ ...options.sortDirection ? { sortDirection: options.sortDirection } : {},
453
+ ...options.includeAdjacent ? { includeAdjacent: true } : {}
454
+ }
455
+ });
456
+ return data;
457
+ }
458
+ /**
459
+ * Lists active members for one organization as a global admin.
460
+ *
461
+ * @param options - Organization ID and pagination options
462
+ * @returns The paginated organization member listing
463
+ */
464
+ async listOrganizationMembers(options) {
465
+ return await this.client.$fetch(`/admin/organizations/${encodeURIComponent(options.organizationId)}/members`, {
466
+ method: "GET",
467
+ query: {
468
+ ...options.limit !== void 0 ? { limit: options.limit } : {},
469
+ ...options.offset !== void 0 ? { offset: options.offset } : {}
470
+ }
471
+ });
472
+ }
473
+ /**
474
+ * Creates an organization without adding the creator as a member.
475
+ *
476
+ * @param options - Organization name and optional slug, logo, metadata, and settings
477
+ * @returns The created organization
478
+ */
479
+ async createOrganization(options) {
480
+ const { data } = await this.client.$fetch("/admin/organizations", {
481
+ method: "POST",
482
+ body: options
483
+ });
484
+ return data;
485
+ }
486
+ /**
487
+ * Updates an organization's profile and settings.
488
+ *
489
+ * @param options - Organization ID and the fields to update
490
+ * @returns The updated organization
491
+ */
492
+ async updateOrganization(options) {
493
+ const { data } = await this.client.$fetch("/admin/organizations/update", {
494
+ method: "POST",
495
+ body: options
496
+ });
497
+ return data;
498
+ }
499
+ /**
500
+ * Bans a user from the auth system and invalidates all their sessions.
501
+ * @param userId - The ID of the user to ban
502
+ */
503
+ async banUser(userId) {
504
+ await this.client.$fetch("/admin/ban-user", { method: "POST", body: { userId } });
505
+ }
506
+ }
507
+
280
508
  class BaseError extends Error {
281
509
  /** Machine-readable error code (e.g. `"INVALID_SOCIAL_PROVIDER"`). */
282
510
  code;
@@ -308,6 +536,20 @@ class AuthorizationFlowError extends ApplicationError {
308
536
  this.code = "AUTHORIZATION_FLOW_ERROR";
309
537
  }
310
538
  }
539
+ class ApplicationSessionAssuranceError extends ApplicationError {
540
+ payload;
541
+ currentAssurance;
542
+ requiredAssurance;
543
+ validStepUps;
544
+ constructor(payload = null, options) {
545
+ super("Session assurance does not meet application policy. Start a new device authorization flow.", options);
546
+ this.code = "APPLICATION_SESSION_ASSURANCE_NOT_MET";
547
+ this.payload = payload;
548
+ this.currentAssurance = payload?.currentAssurance ?? null;
549
+ this.requiredAssurance = payload?.requiredAssurance ?? null;
550
+ this.validStepUps = payload?.validStepUps ?? [];
551
+ }
552
+ }
311
553
  class UserNotLoggedInError extends ApplicationError {
312
554
  constructor(message, options) {
313
555
  super(message, options);
@@ -345,6 +587,174 @@ class DeviceTransientServerError extends ApplicationError {
345
587
  }
346
588
  }
347
589
 
590
+ const OAuthStepUpProvider = z.enum(["google", "microsoft"]);
591
+ const StepUpOption = z.discriminatedUnion("method", [
592
+ z.object({ method: z.literal(AMRs.Pwd) }),
593
+ z.object({ method: z.literal(AMRs.Otp) }),
594
+ z.object({
595
+ method: z.literal(AMRs.Oauth),
596
+ providers: OAuthStepUpProvider.array().min(1)
597
+ })
598
+ ]);
599
+ const SessionAssurancePolicy = z.object({
600
+ minAal: AAL,
601
+ acceptedAmr: AMR.array().min(1)
602
+ });
603
+ const SENSITIVE_ACTION_ASSURANCE_POLICY = {
604
+ minAal: AALs.Aal2,
605
+ acceptedAmr: [AMRs.Pwd, AMRs.Otp, AMRs.Oauth]
606
+ };
607
+ function getAalRank(aal) {
608
+ switch (aal) {
609
+ case AALs.Aal3:
610
+ return 3;
611
+ case AALs.Aal2:
612
+ return 2;
613
+ case AALs.Aal1:
614
+ return 1;
615
+ default:
616
+ return 0;
617
+ }
618
+ }
619
+ function maxAal(left, right) {
620
+ return getAalRank(left) >= getAalRank(right) ? left : right;
621
+ }
622
+ function isAssuranceSufficientForPolicy(assurance, policy) {
623
+ if (!assurance) {
624
+ return false;
625
+ }
626
+ if (getAalRank(assurance.aal) < getAalRank(policy.minAal)) {
627
+ return false;
628
+ }
629
+ if (!assurance.amr.length) {
630
+ return false;
631
+ }
632
+ return assurance.amr.some((amr) => policy.acceptedAmr.includes(amr));
633
+ }
634
+ function canStepUpWithAmr(assurance, amr) {
635
+ return !assurance.amr.includes(amr);
636
+ }
637
+ function mergeStepUpAssurance(assurance, amr, now = /* @__PURE__ */ new Date()) {
638
+ if (!canStepUpWithAmr(assurance, amr)) {
639
+ throw new Error(`AMR ${amr} is already present on the session`);
640
+ }
641
+ return {
642
+ ...assurance,
643
+ amr: [...assurance.amr, amr],
644
+ aal: maxAal(assurance.aal, AALs.Aal2),
645
+ assuredAt: now.toISOString()
646
+ };
647
+ }
648
+
649
+ const SessionAssuranceRequiredCode = z.enum([
650
+ "session_assurance_required",
651
+ "application_session_assurance_not_met"
652
+ ]);
653
+ const SessionAssurancePayloadAssurance = z.preprocess((value) => {
654
+ if (typeof value !== "object" || value === null) {
655
+ return value;
656
+ }
657
+ const assurance = value;
658
+ if (!(assurance.assuredAt instanceof Date)) {
659
+ return value;
660
+ }
661
+ return {
662
+ ...assurance,
663
+ assuredAt: assurance.assuredAt.toISOString()
664
+ };
665
+ }, JWTPayloadAssurance);
666
+ const SessionAssuranceRequiredPayload = z.object({
667
+ code: SessionAssuranceRequiredCode,
668
+ currentAssurance: SessionAssurancePayloadAssurance,
669
+ requiredAssurance: SessionAssurancePolicy,
670
+ validStepUps: StepUpOption.array()
671
+ });
672
+ function getCandidatePayloads(error) {
673
+ const candidate = error;
674
+ return [
675
+ candidate.details,
676
+ candidate.error?.details,
677
+ candidate.data?.details,
678
+ candidate.body?.details,
679
+ candidate.payload,
680
+ error
681
+ ].filter((payload) => payload !== void 0);
682
+ }
683
+ function toSdkCode(code) {
684
+ return code.toUpperCase();
685
+ }
686
+ function parseSessionAssuranceRequiredPayload(error) {
687
+ const seen = /* @__PURE__ */ new Set();
688
+ let current = error;
689
+ while (current && typeof current === "object" && !seen.has(current)) {
690
+ seen.add(current);
691
+ for (const payload of getCandidatePayloads(current)) {
692
+ const result = SessionAssuranceRequiredPayload.safeParse(payload);
693
+ if (result.success) {
694
+ return result.data;
695
+ }
696
+ }
697
+ current = current.cause;
698
+ }
699
+ return null;
700
+ }
701
+ class SessionAssuranceRequiredError extends BaseError {
702
+ payload;
703
+ currentAssurance;
704
+ requiredAssurance;
705
+ validStepUps;
706
+ constructor(payload, options) {
707
+ super(toSdkCode(payload.code), "Session assurance is required for this action", options);
708
+ this.name = "SessionAssuranceRequiredError";
709
+ this.payload = payload;
710
+ this.currentAssurance = payload.currentAssurance;
711
+ this.requiredAssurance = payload.requiredAssurance;
712
+ this.validStepUps = payload.validStepUps;
713
+ }
714
+ }
715
+
716
+ const DEFAULT_SESSION_ASSURANCE_CONFIG = {
717
+ acceptedAmr: [
718
+ AMRs.Pwd,
719
+ AMRs.Oauth,
720
+ AMRs.Saml
721
+ ],
722
+ minAal: AALs.Aal1
723
+ };
724
+ const DEFAULT_APPLICATION_CONFIG = {
725
+ version: 1,
726
+ sessionAssurance: DEFAULT_SESSION_ASSURANCE_CONFIG
727
+ };
728
+ const ApplicationSessionAssuranceConfig = z.object({
729
+ acceptedAmr: AMR.array().optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr),
730
+ minAal: AAL.refine(
731
+ (aal) => aal !== AALs.Aal3,
732
+ "Application session assurance currently supports aal1 and aal2 policies"
733
+ ).optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.minAal)
734
+ });
735
+ const ApplicationConfig = z.object({
736
+ version: z.literal(1),
737
+ sessionAssurance: ApplicationSessionAssuranceConfig.optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG)
738
+ });
739
+
740
+ function allowsDefaultAmrPolicy(config) {
741
+ const acceptedAmr = new Set(config.sessionAssurance.acceptedAmr);
742
+ const defaultAcceptedAmr = DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr;
743
+ return config.sessionAssurance.minAal === DEFAULT_SESSION_ASSURANCE_CONFIG.minAal && defaultAcceptedAmr.every((amr) => acceptedAmr.has(amr));
744
+ }
745
+ function isSessionAssuranceSufficient(sessionAssurance, config = DEFAULT_APPLICATION_CONFIG) {
746
+ if (!sessionAssurance) {
747
+ return false;
748
+ }
749
+ if (!sessionAssurance.amr.length && allowsDefaultAmrPolicy(config)) {
750
+ return getAalRank(sessionAssurance.aal) >= getAalRank(config.sessionAssurance.minAal);
751
+ }
752
+ if (!isAssuranceSufficientForPolicy(sessionAssurance, config.sessionAssurance)) {
753
+ return false;
754
+ }
755
+ return true;
756
+ }
757
+
348
758
  function parseErrorCode(error) {
349
759
  if (!error || typeof error !== "object") {
350
760
  return null;
@@ -376,6 +786,9 @@ function throwDeviceGrantError(error) {
376
786
  if (code === "temporarily_unavailable") {
377
787
  throw new DeviceTransientServerError({ cause: error });
378
788
  }
789
+ if (code === "application_session_assurance_not_met") {
790
+ throw new ApplicationSessionAssuranceError(parseSessionAssuranceRequiredPayload(error), { cause: error });
791
+ }
379
792
  throw new ApplicationError(parseErrorMessage(error), { cause: error });
380
793
  }
381
794
  class ApplicationService {
@@ -425,11 +838,26 @@ class ApplicationService {
425
838
  * @param organizationId - The organization ID to start the authorization flow for
426
839
  */
427
840
  async startAuthorizationFlow(applicationId, redirectUri, codeChallenge, organizationId) {
428
- const response = await this.client.applications.startAuthorizationFlow(applicationId, redirectUri, codeChallenge, organizationId);
429
- if (!response.data) {
430
- throw new Error("No data returned from the API", { cause: response.error });
841
+ try {
842
+ const response = await this.client.applications.startAuthorizationFlow(applicationId, redirectUri, codeChallenge, organizationId);
843
+ if (!response.data) {
844
+ const payload = parseSessionAssuranceRequiredPayload(response.error);
845
+ if (payload) {
846
+ throw new SessionAssuranceRequiredError(payload, { cause: response.error });
847
+ }
848
+ throw new Error("No data returned from the API", { cause: response.error });
849
+ }
850
+ return response.data;
851
+ } catch (error) {
852
+ if (error instanceof SessionAssuranceRequiredError) {
853
+ throw error;
854
+ }
855
+ const payload = parseSessionAssuranceRequiredPayload(error);
856
+ if (payload) {
857
+ throw new SessionAssuranceRequiredError(payload, { cause: error });
858
+ }
859
+ throw error;
431
860
  }
432
- return response.data;
433
861
  }
434
862
  /**
435
863
  * Starts a device authorization flow (RFC 8628).
@@ -505,6 +933,7 @@ class ApplicationService {
505
933
  * @throws {DeviceAccessDeniedError} The user denied the request
506
934
  * @throws {DeviceCodeExpiredError} The device code has expired
507
935
  * @throws {DeviceTransientServerError} Transient server error — safe to retry
936
+ * @throws {ApplicationSessionAssuranceError} Assurance policy changed or is no longer met — start a new flow
508
937
  */
509
938
  async exchangeDeviceCodeForTokens(deviceCode) {
510
939
  try {
@@ -1103,22 +1532,123 @@ class ApiKeyService {
1103
1532
  }
1104
1533
  }
1105
1534
 
1106
- const ApiKeyMetadata = z$1.object({
1107
- user: z$1.object({
1108
- id: z$1.string(),
1109
- email: z$1.string()
1535
+ function getApplicationId(options) {
1536
+ if (!options?.applicationId) {
1537
+ throw new Error("applicationId is required");
1538
+ }
1539
+ return options.applicationId;
1540
+ }
1541
+ class EmailOTPService {
1542
+ /**
1543
+ * Creates a new EmailOTPService instance.
1544
+ *
1545
+ * @param client - The API client for making email OTP requests
1546
+ */
1547
+ constructor(client) {
1548
+ this.client = client;
1549
+ }
1550
+ /**
1551
+ * Sends a sign-in verification OTP to an email address.
1552
+ *
1553
+ * @param email - Email address that should receive the OTP
1554
+ * @param options - Request configuration
1555
+ * @returns The underlying email OTP API response
1556
+ */
1557
+ async sendVerificationOTP(email, options) {
1558
+ const applicationId = getApplicationId(options);
1559
+ return await this.client.emailOtp.sendVerificationOtp({ email, type: "sign-in" }, { query: { applicationId } });
1560
+ }
1561
+ /**
1562
+ * Completes email OTP sign-in with a one-time passcode.
1563
+ *
1564
+ * @param email - Email address that received the OTP
1565
+ * @param otp - One-time passcode from the sign-in email
1566
+ * @param options - Request configuration
1567
+ * @returns The underlying email OTP sign-in API response
1568
+ */
1569
+ async signIn(email, otp, options) {
1570
+ const applicationId = getApplicationId(options);
1571
+ return await this.client.signIn.emailOtp({ email, otp }, { query: { applicationId } });
1572
+ }
1573
+ }
1574
+
1575
+ const ClientJWTPayloadAssurance = JWTPayloadAssurance.extend({
1576
+ assuredAt: z.date()
1577
+ });
1578
+ const SessionAssuranceResponse = z.object({
1579
+ assurance: ClientJWTPayloadAssurance,
1580
+ validStepUps: StepUpOption.array()
1581
+ });
1582
+ const OAuthBeginStepUpResponse = z.object({
1583
+ stepUpToken: z.string(),
1584
+ callbackURL: z.string()
1585
+ });
1586
+ const OAuthCompleteStepUpResponse = SessionAssuranceResponse.extend({
1587
+ returnPath: z.string()
1588
+ });
1589
+ const SendOtpResponse = z.object({
1590
+ success: z.boolean()
1591
+ });
1592
+ function isBetterAuthResponse(response) {
1593
+ return typeof response === "object" && response !== null && "data" in response && "error" in response;
1594
+ }
1595
+ function getResponseData(response) {
1596
+ if (!isBetterAuthResponse(response)) {
1597
+ return response;
1598
+ }
1599
+ if (response.data !== null && response.data !== void 0) {
1600
+ return response.data;
1601
+ }
1602
+ throw new Error("No data returned from the API", { cause: response.error });
1603
+ }
1604
+ function parseResponse(schema, response) {
1605
+ return schema.parse(getResponseData(response));
1606
+ }
1607
+ class SessionAssuranceService {
1608
+ constructor(client) {
1609
+ this.client = client;
1610
+ }
1611
+ async get() {
1612
+ return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.getSessionAssurance());
1613
+ }
1614
+ async stepUpWithPassword(password) {
1615
+ return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.stepUpWithPassword({ password }));
1616
+ }
1617
+ async sendOtp() {
1618
+ return parseResponse(SendOtpResponse, await this.client.sessionAssurance.sendOtp());
1619
+ }
1620
+ async verifyOtp(otp) {
1621
+ return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.verifyOtp({ otp }));
1622
+ }
1623
+ async beginOAuthStepUp(params) {
1624
+ return parseResponse(OAuthBeginStepUpResponse, await this.client.sessionAssurance.beginOAuthStepUp(params));
1625
+ }
1626
+ async completeOAuthStepUp(stepUpToken) {
1627
+ return parseResponse(OAuthCompleteStepUpResponse, await this.client.sessionAssurance.completeOAuthStepUp({ stepUpToken }));
1628
+ }
1629
+ }
1630
+
1631
+ const ApiKeyMetadata = z.object({
1632
+ user: z.object({
1633
+ id: z.string(),
1634
+ email: z.string()
1110
1635
  }),
1111
- workspace: z$1.object({
1112
- id: z$1.string(),
1113
- title: z$1.string()
1636
+ workspace: z.object({
1637
+ id: z.string(),
1638
+ title: z.string()
1114
1639
  }),
1115
- application: z$1.object({
1116
- id: z$1.string(),
1117
- name: z$1.string()
1640
+ application: z.object({
1641
+ id: z.string(),
1642
+ name: z.string()
1118
1643
  }).optional().nullable()
1119
1644
  });
1120
1645
 
1121
1646
  class AuthClient {
1647
+ /**
1648
+ * Configured Better Auth client used by the public service wrappers.
1649
+ *
1650
+ * @internal
1651
+ */
1122
1652
  client;
1123
1653
  /**
1124
1654
  * Session management service for authentication operations
@@ -1136,6 +1666,18 @@ class AuthClient {
1136
1666
  * API key management service for API key operations
1137
1667
  */
1138
1668
  apiKey;
1669
+ /**
1670
+ * Email OTP service for passwordless sign-in operations
1671
+ */
1672
+ emailOtp;
1673
+ /**
1674
+ * Session assurance service for step-up operations
1675
+ */
1676
+ sessionAssurance;
1677
+ /**
1678
+ * Admin service for global admin operations
1679
+ */
1680
+ admin;
1139
1681
  /**
1140
1682
  * Creates a new AuthClient instance.
1141
1683
  *
@@ -1148,6 +1690,9 @@ class AuthClient {
1148
1690
  this.organization = new OrganizationService(this.client);
1149
1691
  this.application = new ApplicationService(this.client);
1150
1692
  this.apiKey = new ApiKeyService(this.client);
1693
+ this.emailOtp = new EmailOTPService(this.client);
1694
+ this.sessionAssurance = new SessionAssuranceService(this.client);
1695
+ this.admin = new AdminService(this.client);
1151
1696
  }
1152
1697
  }
1153
1698
 
@@ -1184,4 +1729,4 @@ function extractTokenPayload(token) {
1184
1729
  return payload;
1185
1730
  }
1186
1731
 
1187
- export { ApiKeyMetadata, ApplicationError, AuthClient, AuthorizationFlowError, DeviceAccessDeniedError, DeviceAuthorizationPendingError, DeviceAuthorizationSlowDownError, DeviceCodeExpiredError, DeviceTransientServerError, EmailRequired, InvalidCallbackURL, InvalidSocialProvider, JWTPayload, JWTPayloadUser, JWTPayloadWorkspace, RefreshTokenExpiredError, Roles, UserNotLoggedInError, ac, extractTokenPayload, invitationAdditionalFields, isTokenExpired, memberAdditionalFields, organizationAdditionalFields, rolesAccessControl, userAdditionalFields, validateToken };
1732
+ export { AAL, AALBrand, AALs, ACR, ACRBrand, ACRs, AMR, AMRBrand, AMRs, ApiKeyMetadata, ApplicationConfig, ApplicationError, ApplicationSessionAssuranceConfig, ApplicationSessionAssuranceError, AuthClient, AuthMethod, AuthMethodBrand, AuthMethods, AuthorizationFlowError, DEFAULT_APPLICATION_CONFIG, DEFAULT_JWT_ASSURANCE, DEFAULT_SESSION_ASSURANCE_CONFIG, DeviceAccessDeniedError, DeviceAuthorizationPendingError, DeviceAuthorizationSlowDownError, DeviceCodeExpiredError, DeviceTransientServerError, EmailOTPService, EmailRequired, InvalidCallbackURL, InvalidSocialProvider, JWTPayload, JWTPayloadAssurance, JWTPayloadUser, JWTPayloadWorkspace, OAuthStepUpProvider, RefreshTokenExpiredError, Roles, SENSITIVE_ACTION_ASSURANCE_POLICY, SessionAssurancePolicy, SessionAssuranceRequiredError, SessionAssuranceRequiredPayload, SessionAssuranceService, StepUpOption, UserNotLoggedInError, ac, assuranceFields, canStepUpWithAmr, extractTokenPayload, getAalRank, invitationAdditionalFields, isAssuranceSufficientForPolicy, isSessionAssuranceSufficient, isTokenExpired, memberAdditionalFields, mergeStepUpAssurance, organizationAdditionalFields, parseSessionAssuranceRequiredPayload, rolesAccessControl, sessionAssurancePluginClient, userAdditionalFields, validateToken };