@meistrari/auth-core 1.20.0 → 1.21.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.d.mts +796 -63
- package/dist/index.d.ts +796 -63
- package/dist/index.mjs +457 -32
- package/package.json +1 -1
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
|
|
8
|
+
import z, { z as z$1 } from 'zod';
|
|
9
9
|
export { APIError } from 'better-auth';
|
|
10
10
|
|
|
11
|
-
const version = "1.
|
|
11
|
+
const version = "1.21.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()
|
|
76
138
|
});
|
|
77
|
-
const JWTPayloadWorkspace = z.object({
|
|
78
|
-
id: z.string(),
|
|
79
|
-
title: z.string()
|
|
139
|
+
const JWTPayloadWorkspace = z$1.object({
|
|
140
|
+
id: z$1.string(),
|
|
141
|
+
title: z$1.string()
|
|
80
142
|
});
|
|
81
|
-
const
|
|
82
|
-
|
|
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()
|
|
149
|
+
});
|
|
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,
|
|
@@ -308,6 +415,20 @@ class AuthorizationFlowError extends ApplicationError {
|
|
|
308
415
|
this.code = "AUTHORIZATION_FLOW_ERROR";
|
|
309
416
|
}
|
|
310
417
|
}
|
|
418
|
+
class ApplicationSessionAssuranceError extends ApplicationError {
|
|
419
|
+
payload;
|
|
420
|
+
currentAssurance;
|
|
421
|
+
requiredAssurance;
|
|
422
|
+
validStepUps;
|
|
423
|
+
constructor(payload = null, options) {
|
|
424
|
+
super("Session assurance does not meet application policy. Start a new device authorization flow.", options);
|
|
425
|
+
this.code = "APPLICATION_SESSION_ASSURANCE_NOT_MET";
|
|
426
|
+
this.payload = payload;
|
|
427
|
+
this.currentAssurance = payload?.currentAssurance ?? null;
|
|
428
|
+
this.requiredAssurance = payload?.requiredAssurance ?? null;
|
|
429
|
+
this.validStepUps = payload?.validStepUps ?? [];
|
|
430
|
+
}
|
|
431
|
+
}
|
|
311
432
|
class UserNotLoggedInError extends ApplicationError {
|
|
312
433
|
constructor(message, options) {
|
|
313
434
|
super(message, options);
|
|
@@ -345,6 +466,174 @@ class DeviceTransientServerError extends ApplicationError {
|
|
|
345
466
|
}
|
|
346
467
|
}
|
|
347
468
|
|
|
469
|
+
const OAuthStepUpProvider = z.enum(["google", "microsoft"]);
|
|
470
|
+
const StepUpOption = z.discriminatedUnion("method", [
|
|
471
|
+
z.object({ method: z.literal(AMRs.Pwd) }),
|
|
472
|
+
z.object({ method: z.literal(AMRs.Otp) }),
|
|
473
|
+
z.object({
|
|
474
|
+
method: z.literal(AMRs.Oauth),
|
|
475
|
+
providers: OAuthStepUpProvider.array().min(1)
|
|
476
|
+
})
|
|
477
|
+
]);
|
|
478
|
+
const SessionAssurancePolicy = z.object({
|
|
479
|
+
minAal: AAL,
|
|
480
|
+
acceptedAmr: AMR.array().min(1)
|
|
481
|
+
});
|
|
482
|
+
const SENSITIVE_ACTION_ASSURANCE_POLICY = {
|
|
483
|
+
minAal: AALs.Aal2,
|
|
484
|
+
acceptedAmr: [AMRs.Pwd, AMRs.Otp, AMRs.Oauth]
|
|
485
|
+
};
|
|
486
|
+
function getAalRank(aal) {
|
|
487
|
+
switch (aal) {
|
|
488
|
+
case AALs.Aal3:
|
|
489
|
+
return 3;
|
|
490
|
+
case AALs.Aal2:
|
|
491
|
+
return 2;
|
|
492
|
+
case AALs.Aal1:
|
|
493
|
+
return 1;
|
|
494
|
+
default:
|
|
495
|
+
return 0;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
function maxAal(left, right) {
|
|
499
|
+
return getAalRank(left) >= getAalRank(right) ? left : right;
|
|
500
|
+
}
|
|
501
|
+
function isAssuranceSufficientForPolicy(assurance, policy) {
|
|
502
|
+
if (!assurance) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
if (getAalRank(assurance.aal) < getAalRank(policy.minAal)) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (!assurance.amr.length) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
return assurance.amr.some((amr) => policy.acceptedAmr.includes(amr));
|
|
512
|
+
}
|
|
513
|
+
function canStepUpWithAmr(assurance, amr) {
|
|
514
|
+
return !assurance.amr.includes(amr);
|
|
515
|
+
}
|
|
516
|
+
function mergeStepUpAssurance(assurance, amr, now = /* @__PURE__ */ new Date()) {
|
|
517
|
+
if (!canStepUpWithAmr(assurance, amr)) {
|
|
518
|
+
throw new Error(`AMR ${amr} is already present on the session`);
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
...assurance,
|
|
522
|
+
amr: [...assurance.amr, amr],
|
|
523
|
+
aal: maxAal(assurance.aal, AALs.Aal2),
|
|
524
|
+
assuredAt: now.toISOString()
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const SessionAssuranceRequiredCode = z.enum([
|
|
529
|
+
"session_assurance_required",
|
|
530
|
+
"application_session_assurance_not_met"
|
|
531
|
+
]);
|
|
532
|
+
const SessionAssurancePayloadAssurance = z.preprocess((value) => {
|
|
533
|
+
if (typeof value !== "object" || value === null) {
|
|
534
|
+
return value;
|
|
535
|
+
}
|
|
536
|
+
const assurance = value;
|
|
537
|
+
if (!(assurance.assuredAt instanceof Date)) {
|
|
538
|
+
return value;
|
|
539
|
+
}
|
|
540
|
+
return {
|
|
541
|
+
...assurance,
|
|
542
|
+
assuredAt: assurance.assuredAt.toISOString()
|
|
543
|
+
};
|
|
544
|
+
}, JWTPayloadAssurance);
|
|
545
|
+
const SessionAssuranceRequiredPayload = z.object({
|
|
546
|
+
code: SessionAssuranceRequiredCode,
|
|
547
|
+
currentAssurance: SessionAssurancePayloadAssurance,
|
|
548
|
+
requiredAssurance: SessionAssurancePolicy,
|
|
549
|
+
validStepUps: StepUpOption.array()
|
|
550
|
+
});
|
|
551
|
+
function getCandidatePayloads(error) {
|
|
552
|
+
const candidate = error;
|
|
553
|
+
return [
|
|
554
|
+
candidate.details,
|
|
555
|
+
candidate.error?.details,
|
|
556
|
+
candidate.data?.details,
|
|
557
|
+
candidate.body?.details,
|
|
558
|
+
candidate.payload,
|
|
559
|
+
error
|
|
560
|
+
].filter((payload) => payload !== void 0);
|
|
561
|
+
}
|
|
562
|
+
function toSdkCode(code) {
|
|
563
|
+
return code.toUpperCase();
|
|
564
|
+
}
|
|
565
|
+
function parseSessionAssuranceRequiredPayload(error) {
|
|
566
|
+
const seen = /* @__PURE__ */ new Set();
|
|
567
|
+
let current = error;
|
|
568
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
569
|
+
seen.add(current);
|
|
570
|
+
for (const payload of getCandidatePayloads(current)) {
|
|
571
|
+
const result = SessionAssuranceRequiredPayload.safeParse(payload);
|
|
572
|
+
if (result.success) {
|
|
573
|
+
return result.data;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
current = current.cause;
|
|
577
|
+
}
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
class SessionAssuranceRequiredError extends BaseError {
|
|
581
|
+
payload;
|
|
582
|
+
currentAssurance;
|
|
583
|
+
requiredAssurance;
|
|
584
|
+
validStepUps;
|
|
585
|
+
constructor(payload, options) {
|
|
586
|
+
super(toSdkCode(payload.code), "Session assurance is required for this action", options);
|
|
587
|
+
this.name = "SessionAssuranceRequiredError";
|
|
588
|
+
this.payload = payload;
|
|
589
|
+
this.currentAssurance = payload.currentAssurance;
|
|
590
|
+
this.requiredAssurance = payload.requiredAssurance;
|
|
591
|
+
this.validStepUps = payload.validStepUps;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const DEFAULT_SESSION_ASSURANCE_CONFIG = {
|
|
596
|
+
acceptedAmr: [
|
|
597
|
+
AMRs.Pwd,
|
|
598
|
+
AMRs.Oauth,
|
|
599
|
+
AMRs.Saml
|
|
600
|
+
],
|
|
601
|
+
minAal: AALs.Aal1
|
|
602
|
+
};
|
|
603
|
+
const DEFAULT_APPLICATION_CONFIG = {
|
|
604
|
+
version: 1,
|
|
605
|
+
sessionAssurance: DEFAULT_SESSION_ASSURANCE_CONFIG
|
|
606
|
+
};
|
|
607
|
+
const ApplicationSessionAssuranceConfig = z.object({
|
|
608
|
+
acceptedAmr: AMR.array().optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr),
|
|
609
|
+
minAal: AAL.refine(
|
|
610
|
+
(aal) => aal !== AALs.Aal3,
|
|
611
|
+
"Application session assurance currently supports aal1 and aal2 policies"
|
|
612
|
+
).optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG.minAal)
|
|
613
|
+
});
|
|
614
|
+
const ApplicationConfig = z.object({
|
|
615
|
+
version: z.literal(1),
|
|
616
|
+
sessionAssurance: ApplicationSessionAssuranceConfig.optional().default(DEFAULT_SESSION_ASSURANCE_CONFIG)
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
function allowsDefaultAmrPolicy(config) {
|
|
620
|
+
const acceptedAmr = new Set(config.sessionAssurance.acceptedAmr);
|
|
621
|
+
const defaultAcceptedAmr = DEFAULT_SESSION_ASSURANCE_CONFIG.acceptedAmr;
|
|
622
|
+
return config.sessionAssurance.minAal === DEFAULT_SESSION_ASSURANCE_CONFIG.minAal && defaultAcceptedAmr.every((amr) => acceptedAmr.has(amr));
|
|
623
|
+
}
|
|
624
|
+
function isSessionAssuranceSufficient(sessionAssurance, config = DEFAULT_APPLICATION_CONFIG) {
|
|
625
|
+
if (!sessionAssurance) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
if (!sessionAssurance.amr.length && allowsDefaultAmrPolicy(config)) {
|
|
629
|
+
return getAalRank(sessionAssurance.aal) >= getAalRank(config.sessionAssurance.minAal);
|
|
630
|
+
}
|
|
631
|
+
if (!isAssuranceSufficientForPolicy(sessionAssurance, config.sessionAssurance)) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
|
|
348
637
|
function parseErrorCode(error) {
|
|
349
638
|
if (!error || typeof error !== "object") {
|
|
350
639
|
return null;
|
|
@@ -376,6 +665,9 @@ function throwDeviceGrantError(error) {
|
|
|
376
665
|
if (code === "temporarily_unavailable") {
|
|
377
666
|
throw new DeviceTransientServerError({ cause: error });
|
|
378
667
|
}
|
|
668
|
+
if (code === "application_session_assurance_not_met") {
|
|
669
|
+
throw new ApplicationSessionAssuranceError(parseSessionAssuranceRequiredPayload(error), { cause: error });
|
|
670
|
+
}
|
|
379
671
|
throw new ApplicationError(parseErrorMessage(error), { cause: error });
|
|
380
672
|
}
|
|
381
673
|
class ApplicationService {
|
|
@@ -425,11 +717,26 @@ class ApplicationService {
|
|
|
425
717
|
* @param organizationId - The organization ID to start the authorization flow for
|
|
426
718
|
*/
|
|
427
719
|
async startAuthorizationFlow(applicationId, redirectUri, codeChallenge, organizationId) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
720
|
+
try {
|
|
721
|
+
const response = await this.client.applications.startAuthorizationFlow(applicationId, redirectUri, codeChallenge, organizationId);
|
|
722
|
+
if (!response.data) {
|
|
723
|
+
const payload = parseSessionAssuranceRequiredPayload(response.error);
|
|
724
|
+
if (payload) {
|
|
725
|
+
throw new SessionAssuranceRequiredError(payload, { cause: response.error });
|
|
726
|
+
}
|
|
727
|
+
throw new Error("No data returned from the API", { cause: response.error });
|
|
728
|
+
}
|
|
729
|
+
return response.data;
|
|
730
|
+
} catch (error) {
|
|
731
|
+
if (error instanceof SessionAssuranceRequiredError) {
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
734
|
+
const payload = parseSessionAssuranceRequiredPayload(error);
|
|
735
|
+
if (payload) {
|
|
736
|
+
throw new SessionAssuranceRequiredError(payload, { cause: error });
|
|
737
|
+
}
|
|
738
|
+
throw error;
|
|
431
739
|
}
|
|
432
|
-
return response.data;
|
|
433
740
|
}
|
|
434
741
|
/**
|
|
435
742
|
* Starts a device authorization flow (RFC 8628).
|
|
@@ -505,6 +812,7 @@ class ApplicationService {
|
|
|
505
812
|
* @throws {DeviceAccessDeniedError} The user denied the request
|
|
506
813
|
* @throws {DeviceCodeExpiredError} The device code has expired
|
|
507
814
|
* @throws {DeviceTransientServerError} Transient server error — safe to retry
|
|
815
|
+
* @throws {ApplicationSessionAssuranceError} Assurance policy changed or is no longer met — start a new flow
|
|
508
816
|
*/
|
|
509
817
|
async exchangeDeviceCodeForTokens(deviceCode) {
|
|
510
818
|
try {
|
|
@@ -960,14 +1268,20 @@ class SessionService {
|
|
|
960
1268
|
* @param options - Email/password sign-in configuration
|
|
961
1269
|
* @param options.email - User's email address
|
|
962
1270
|
* @param options.password - User's password
|
|
1271
|
+
* @param options.callbackURL - URL to redirect to after successful authentication
|
|
963
1272
|
*/
|
|
964
1273
|
async signInWithEmailAndPassword({
|
|
965
1274
|
email,
|
|
966
|
-
password
|
|
1275
|
+
password,
|
|
1276
|
+
callbackURL
|
|
967
1277
|
}) {
|
|
1278
|
+
if (!isValidUrl(callbackURL)) {
|
|
1279
|
+
throw new InvalidCallbackURL(`Invalid callback URL: ${callbackURL}`);
|
|
1280
|
+
}
|
|
968
1281
|
await this.client.signIn.email({
|
|
969
1282
|
email,
|
|
970
|
-
password
|
|
1283
|
+
password,
|
|
1284
|
+
callbackURL
|
|
971
1285
|
});
|
|
972
1286
|
}
|
|
973
1287
|
/**
|
|
@@ -1097,22 +1411,123 @@ class ApiKeyService {
|
|
|
1097
1411
|
}
|
|
1098
1412
|
}
|
|
1099
1413
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1414
|
+
function getApplicationId(options) {
|
|
1415
|
+
if (!options?.applicationId) {
|
|
1416
|
+
throw new Error("applicationId is required");
|
|
1417
|
+
}
|
|
1418
|
+
return options.applicationId;
|
|
1419
|
+
}
|
|
1420
|
+
class EmailOTPService {
|
|
1421
|
+
/**
|
|
1422
|
+
* Creates a new EmailOTPService instance.
|
|
1423
|
+
*
|
|
1424
|
+
* @param client - The API client for making email OTP requests
|
|
1425
|
+
*/
|
|
1426
|
+
constructor(client) {
|
|
1427
|
+
this.client = client;
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Sends a sign-in verification OTP to an email address.
|
|
1431
|
+
*
|
|
1432
|
+
* @param email - Email address that should receive the OTP
|
|
1433
|
+
* @param options - Request configuration
|
|
1434
|
+
* @returns The underlying email OTP API response
|
|
1435
|
+
*/
|
|
1436
|
+
async sendVerificationOTP(email, options) {
|
|
1437
|
+
const applicationId = getApplicationId(options);
|
|
1438
|
+
return await this.client.emailOtp.sendVerificationOtp({ email, type: "sign-in" }, { query: { applicationId } });
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Completes email OTP sign-in with a one-time passcode.
|
|
1442
|
+
*
|
|
1443
|
+
* @param email - Email address that received the OTP
|
|
1444
|
+
* @param otp - One-time passcode from the sign-in email
|
|
1445
|
+
* @param options - Request configuration
|
|
1446
|
+
* @returns The underlying email OTP sign-in API response
|
|
1447
|
+
*/
|
|
1448
|
+
async signIn(email, otp, options) {
|
|
1449
|
+
const applicationId = getApplicationId(options);
|
|
1450
|
+
return await this.client.signIn.emailOtp({ email, otp }, { query: { applicationId } });
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
const ClientJWTPayloadAssurance = JWTPayloadAssurance.extend({
|
|
1455
|
+
assuredAt: z.date()
|
|
1456
|
+
});
|
|
1457
|
+
const SessionAssuranceResponse = z.object({
|
|
1458
|
+
assurance: ClientJWTPayloadAssurance,
|
|
1459
|
+
validStepUps: StepUpOption.array()
|
|
1460
|
+
});
|
|
1461
|
+
const OAuthBeginStepUpResponse = z.object({
|
|
1462
|
+
stepUpToken: z.string(),
|
|
1463
|
+
callbackURL: z.string()
|
|
1464
|
+
});
|
|
1465
|
+
const OAuthCompleteStepUpResponse = SessionAssuranceResponse.extend({
|
|
1466
|
+
returnPath: z.string()
|
|
1467
|
+
});
|
|
1468
|
+
const SendOtpResponse = z.object({
|
|
1469
|
+
success: z.boolean()
|
|
1470
|
+
});
|
|
1471
|
+
function isBetterAuthResponse(response) {
|
|
1472
|
+
return typeof response === "object" && response !== null && "data" in response && "error" in response;
|
|
1473
|
+
}
|
|
1474
|
+
function getResponseData(response) {
|
|
1475
|
+
if (!isBetterAuthResponse(response)) {
|
|
1476
|
+
return response;
|
|
1477
|
+
}
|
|
1478
|
+
if (response.data !== null && response.data !== void 0) {
|
|
1479
|
+
return response.data;
|
|
1480
|
+
}
|
|
1481
|
+
throw new Error("No data returned from the API", { cause: response.error });
|
|
1482
|
+
}
|
|
1483
|
+
function parseResponse(schema, response) {
|
|
1484
|
+
return schema.parse(getResponseData(response));
|
|
1485
|
+
}
|
|
1486
|
+
class SessionAssuranceService {
|
|
1487
|
+
constructor(client) {
|
|
1488
|
+
this.client = client;
|
|
1489
|
+
}
|
|
1490
|
+
async get() {
|
|
1491
|
+
return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.getSessionAssurance());
|
|
1492
|
+
}
|
|
1493
|
+
async stepUpWithPassword(password) {
|
|
1494
|
+
return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.stepUpWithPassword({ password }));
|
|
1495
|
+
}
|
|
1496
|
+
async sendOtp() {
|
|
1497
|
+
return parseResponse(SendOtpResponse, await this.client.sessionAssurance.sendOtp());
|
|
1498
|
+
}
|
|
1499
|
+
async verifyOtp(otp) {
|
|
1500
|
+
return parseResponse(SessionAssuranceResponse, await this.client.sessionAssurance.verifyOtp({ otp }));
|
|
1501
|
+
}
|
|
1502
|
+
async beginOAuthStepUp(params) {
|
|
1503
|
+
return parseResponse(OAuthBeginStepUpResponse, await this.client.sessionAssurance.beginOAuthStepUp(params));
|
|
1504
|
+
}
|
|
1505
|
+
async completeOAuthStepUp(stepUpToken) {
|
|
1506
|
+
return parseResponse(OAuthCompleteStepUpResponse, await this.client.sessionAssurance.completeOAuthStepUp({ stepUpToken }));
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
const ApiKeyMetadata = z.object({
|
|
1511
|
+
user: z.object({
|
|
1512
|
+
id: z.string(),
|
|
1513
|
+
email: z.string()
|
|
1104
1514
|
}),
|
|
1105
|
-
workspace: z
|
|
1106
|
-
id: z
|
|
1107
|
-
title: z
|
|
1515
|
+
workspace: z.object({
|
|
1516
|
+
id: z.string(),
|
|
1517
|
+
title: z.string()
|
|
1108
1518
|
}),
|
|
1109
|
-
application: z
|
|
1110
|
-
id: z
|
|
1111
|
-
name: z
|
|
1519
|
+
application: z.object({
|
|
1520
|
+
id: z.string(),
|
|
1521
|
+
name: z.string()
|
|
1112
1522
|
}).optional().nullable()
|
|
1113
1523
|
});
|
|
1114
1524
|
|
|
1115
1525
|
class AuthClient {
|
|
1526
|
+
/**
|
|
1527
|
+
* Configured Better Auth client used by the public service wrappers.
|
|
1528
|
+
*
|
|
1529
|
+
* @internal
|
|
1530
|
+
*/
|
|
1116
1531
|
client;
|
|
1117
1532
|
/**
|
|
1118
1533
|
* Session management service for authentication operations
|
|
@@ -1130,6 +1545,14 @@ class AuthClient {
|
|
|
1130
1545
|
* API key management service for API key operations
|
|
1131
1546
|
*/
|
|
1132
1547
|
apiKey;
|
|
1548
|
+
/**
|
|
1549
|
+
* Email OTP service for passwordless sign-in operations
|
|
1550
|
+
*/
|
|
1551
|
+
emailOtp;
|
|
1552
|
+
/**
|
|
1553
|
+
* Session assurance service for step-up operations
|
|
1554
|
+
*/
|
|
1555
|
+
sessionAssurance;
|
|
1133
1556
|
/**
|
|
1134
1557
|
* Creates a new AuthClient instance.
|
|
1135
1558
|
*
|
|
@@ -1142,6 +1565,8 @@ class AuthClient {
|
|
|
1142
1565
|
this.organization = new OrganizationService(this.client);
|
|
1143
1566
|
this.application = new ApplicationService(this.client);
|
|
1144
1567
|
this.apiKey = new ApiKeyService(this.client);
|
|
1568
|
+
this.emailOtp = new EmailOTPService(this.client);
|
|
1569
|
+
this.sessionAssurance = new SessionAssuranceService(this.client);
|
|
1145
1570
|
}
|
|
1146
1571
|
}
|
|
1147
1572
|
|
|
@@ -1178,4 +1603,4 @@ function extractTokenPayload(token) {
|
|
|
1178
1603
|
return payload;
|
|
1179
1604
|
}
|
|
1180
1605
|
|
|
1181
|
-
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 };
|
|
1606
|
+
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 };
|