@cboxdk/id-js 0.18.0 → 0.19.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/README.md +97 -1
- package/dist/{chunk-CXGKOJRJ.js → chunk-YGLMLIKL.js} +144 -9
- package/dist/chunk-YGLMLIKL.js.map +1 -0
- package/dist/{client-BxUHm5hX.d.cts → client-BT-jOm0p.d.cts} +126 -2
- package/dist/{client-BSZASrMo.d.ts → client-xlEJalu8.d.ts} +126 -2
- package/dist/index.cjs +211 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -6
- package/dist/index.d.ts +83 -6
- package/dist/index.js +63 -11
- package/dist/index.js.map +1 -1
- package/dist/management.cjs +726 -6
- package/dist/management.cjs.map +1 -1
- package/dist/management.d.cts +2557 -26
- package/dist/management.d.ts +2557 -26
- package/dist/management.js +726 -7
- package/dist/management.js.map +1 -1
- package/dist/nextjs.cjs +136 -5
- package/dist/nextjs.cjs.map +1 -1
- package/dist/nextjs.d.cts +3 -2
- package/dist/nextjs.d.ts +3 -2
- package/dist/nextjs.js +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/{types-BYZldock.d.cts → types-CC1bz68x.d.cts} +30 -1
- package/dist/{types-BYZldock.d.ts → types-CC1bz68x.d.ts} +30 -1
- package/package.json +1 -1
- package/dist/chunk-CXGKOJRJ.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { A as AuthenticationError, C as CboxIdError, a as ConfigurationError, F as FrontendApiError, I as InvalidStateError } from './errors-D61xljZE.cjs';
|
|
2
|
-
export { a as CallbackParams, C as CboxIdClient, S as StoreSecretInput,
|
|
3
|
-
export { c as AuthorizationPrompt, b as AuthorizationRequest, A as AuthorizationRequestOptions, d as CboxActiveOrganization, e as CboxActor, a as CboxIdConfig, f as CboxOrganization, C as CboxUser, g as ClaimSource, D as DeviceAuthorization, h as DiscoveryDocument, O as OrganizationRole, R as RefreshedTokens, i as TokenResponse, T as TokenTypeHint, j as actor, k as
|
|
2
|
+
export { a as CallbackParams, C as CboxIdClient, P as PipeConnectOptions, b as PipeLeaseDeniedError, c as PipeLeaseError, d as PipeNotConnectedError, e as PipeProvider, f as PipeReauthorizationRequiredError, g as PipeTemporarilyUnavailableError, h as PipeToken, S as StoreSecretInput, i as StoredAuthState, V as VaultClient, j as VaultLease, k as VaultSecretRef, l as VerifyStandardWebhookOptions, m as VerifyWebhookOptions, W as WebhookHeaders, p as pipeConnectUrl, v as verifyStandardWebhook, n as verifyWebhook, w as withConnectReturn } from './client-BT-jOm0p.cjs';
|
|
3
|
+
export { c as AuthorizationPrompt, b as AuthorizationRequest, A as AuthorizationRequestOptions, d as CboxActiveOrganization, e as CboxActor, a as CboxIdConfig, f as CboxOrganization, C as CboxUser, g as ClaimSource, D as DeviceAuthorization, h as DiscoveryDocument, F as FEATURE_FLAGS_SCOPE, O as OrganizationRole, R as RefreshedTokens, i as TokenResponse, T as TokenTypeHint, j as actor, k as featureFlags, l as hasFeature, m as hasPermission, n as hasRole, o as isSupportSession, p as organization, q as permissions, r as roles, s as sessionId } from './types-CC1bz68x.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The handler on YOUR side of a legacy migration.
|
|
@@ -130,9 +130,35 @@ interface FrontendConfig {
|
|
|
130
130
|
end_session: string;
|
|
131
131
|
jwks: string;
|
|
132
132
|
};
|
|
133
|
+
/**
|
|
134
|
+
* The social buttons to draw, exactly as the hosted sign-in page would: the environment's
|
|
135
|
+
* own providers, or — with `config({ organization })` — that organization's.
|
|
136
|
+
*/
|
|
133
137
|
social: SocialProvider[];
|
|
134
138
|
appearance?: Appearance;
|
|
139
|
+
/**
|
|
140
|
+
* Which other sign-in methods are switched on, so a box does not draw a button whose
|
|
141
|
+
* endpoint answers 403. Absent from instances that predate it.
|
|
142
|
+
*/
|
|
143
|
+
methods?: {
|
|
144
|
+
passkeys: boolean;
|
|
145
|
+
magic_link: boolean;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** Options for {@link CboxIdFrontend.config}. */
|
|
149
|
+
interface FrontendConfigOptions {
|
|
150
|
+
/**
|
|
151
|
+
* The organization the box is for, by id or slug — the way a hosted page is addressed.
|
|
152
|
+
* `social` is then exactly what that organization's sign-in page offers. An organization
|
|
153
|
+
* the environment does not have is answered as no hint at all.
|
|
154
|
+
*/
|
|
155
|
+
organization?: string;
|
|
135
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* A second factor the person can answer an `mfa_required` with. Kinds only — the server
|
|
159
|
+
* never says which number a text would go to before one is sent.
|
|
160
|
+
*/
|
|
161
|
+
type SecondFactorKind = 'totp' | 'sms' | 'recovery_code';
|
|
136
162
|
/** What a sign-in attempt produced. */
|
|
137
163
|
type SignInResult = {
|
|
138
164
|
status: 'ok';
|
|
@@ -141,6 +167,11 @@ type SignInResult = {
|
|
|
141
167
|
} | {
|
|
142
168
|
status: 'mfa_required';
|
|
143
169
|
mfaToken: string;
|
|
170
|
+
/**
|
|
171
|
+
* The factors this person can answer with (laravel-id 1.24+). Absent when the
|
|
172
|
+
* instance predates the list — then only an authenticator or a recovery code works.
|
|
173
|
+
*/
|
|
174
|
+
factors?: SecondFactorKind[];
|
|
144
175
|
} | {
|
|
145
176
|
status: 'otp_required';
|
|
146
177
|
mfaToken: string;
|
|
@@ -152,6 +183,30 @@ type SignInResult = {
|
|
|
152
183
|
status: 'rate_limited';
|
|
153
184
|
retryAfter: number | undefined;
|
|
154
185
|
};
|
|
186
|
+
/** What asking for a texted sign-in code produced. */
|
|
187
|
+
type SmsCodeResult =
|
|
188
|
+
/** Sent. `to` is the number masked (`+45 ******78`); the code lasts `expiresIn` seconds. */
|
|
189
|
+
{
|
|
190
|
+
status: 'sent';
|
|
191
|
+
to: string;
|
|
192
|
+
expiresIn: number;
|
|
193
|
+
}
|
|
194
|
+
/** Too soon, or a sending limit was hit. Waiting `retryAfter` seconds may help. */
|
|
195
|
+
| {
|
|
196
|
+
status: 'rate_limited';
|
|
197
|
+
retryAfter: number | undefined;
|
|
198
|
+
}
|
|
199
|
+
/** The text provider failed. Try again shortly, or offer another factor. */
|
|
200
|
+
| {
|
|
201
|
+
status: 'unavailable';
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Refused: an unknown or spent token, no number on file, a country texts are not sent
|
|
205
|
+
* to, or no attempts left. One answer for every reason, like a wrong password.
|
|
206
|
+
*/
|
|
207
|
+
| {
|
|
208
|
+
status: 'invalid';
|
|
209
|
+
};
|
|
155
210
|
/** What a browser needs to ask an authenticator for a passkey assertion. */
|
|
156
211
|
interface PasskeyOptions {
|
|
157
212
|
challenge: string;
|
|
@@ -197,7 +252,7 @@ declare class CboxIdFrontend {
|
|
|
197
252
|
* fetches of the same immutable document is a waste the SDK should absorb rather than
|
|
198
253
|
* ask every consumer to.
|
|
199
254
|
*/
|
|
200
|
-
private
|
|
255
|
+
private readonly configPromises;
|
|
201
256
|
constructor(options: FrontendClientOptions);
|
|
202
257
|
/** Whether this key drives real sign-ins. Handy for a "test mode" badge in your own UI. */
|
|
203
258
|
get isLive(): boolean;
|
|
@@ -207,8 +262,9 @@ declare class CboxIdFrontend {
|
|
|
207
262
|
* Fetched once per client instance. The document is small and changes when somebody
|
|
208
263
|
* edits it in the console, so a long-lived page picks changes up on its next full load
|
|
209
264
|
* rather than mid-session — which is the right trade for something that decides layout.
|
|
265
|
+
* Each `organization` is fetched and cached on its own.
|
|
210
266
|
*/
|
|
211
|
-
config(): Promise<FrontendConfig>;
|
|
267
|
+
config(options?: FrontendConfigOptions): Promise<FrontendConfig>;
|
|
212
268
|
/**
|
|
213
269
|
* Who is signed in, given an access token your app already holds.
|
|
214
270
|
*
|
|
@@ -256,8 +312,29 @@ declare class CboxIdFrontend {
|
|
|
256
312
|
*
|
|
257
313
|
* A wrong code costs an attempt, not the sign-in: five are allowed before the token
|
|
258
314
|
* dies and the person starts from the password again.
|
|
315
|
+
*
|
|
316
|
+
* `method` says which challenge the code answers: `'mfa'` for an authenticator or
|
|
317
|
+
* recovery code, `'otp'` for an emailed code (`otp_required`), `'sms'` for a code sent
|
|
318
|
+
* with {@link sendSmsCode}. A texted code is six digits like an authenticator's, so the
|
|
319
|
+
* server cannot tell them apart by shape — answering one as the other is refused.
|
|
320
|
+
*/
|
|
321
|
+
submitSecondFactor(mfaToken: string, code: string, method?: 'mfa' | 'otp' | 'sms'): Promise<SignInResult>;
|
|
322
|
+
/**
|
|
323
|
+
* Text the person a sign-in code, when `mfa_required` listed `'sms'` in `factors`.
|
|
324
|
+
* Then finish with `submitSecondFactor(mfaToken, code, 'sms')`.
|
|
325
|
+
*
|
|
326
|
+
* Only call it when the person asks ("Text me a code"), never on page load: each send
|
|
327
|
+
* spends one of the token's five attempts — that is what bounds how many texts one
|
|
328
|
+
* proved password can cause — and every text costs the customer money.
|
|
329
|
+
*
|
|
330
|
+
* ```ts
|
|
331
|
+
* if (result.status === 'mfa_required' && result.factors?.includes('sms')) {
|
|
332
|
+
* const sent = await frontend.sendSmsCode(result.mfaToken)
|
|
333
|
+
* if (sent.status === 'sent') showCodeField(`We texted ${sent.to}`)
|
|
334
|
+
* }
|
|
335
|
+
* ```
|
|
259
336
|
*/
|
|
260
|
-
|
|
337
|
+
sendSmsCode(mfaToken: string): Promise<SmsCodeResult>;
|
|
261
338
|
/**
|
|
262
339
|
* The WebAuthn options for a passkey sign-in, and the handle that carries the challenge.
|
|
263
340
|
*
|
|
@@ -442,4 +519,4 @@ declare function buildManifest(declaration: AuthzDeclaration): Promise<AuthzMani
|
|
|
442
519
|
*/
|
|
443
520
|
declare function publishManifest(config: ManifestPublisherConfig, declaration: AuthzDeclaration): Promise<ManifestSyncSummary>;
|
|
444
521
|
|
|
445
|
-
export { type Appearance, type AuthzDeclaration, type AuthzManifest, CboxIdFrontend, type FrontendClientOptions, type FrontendConfig, type FrontendSession, type LegacyUser, type LegacyVerifierOptions, type ManifestPermission, type ManifestPublisherConfig, type ManifestRole, type ManifestSyncSummary, type PasskeyOptions, type PermissionDefinition, type RoleDefinition, type SignInResult, type SocialProvider, buildManifest, challenge, createLegacyVerifier, createVerifier, defineAuthz, publishManifest, randomToken };
|
|
522
|
+
export { type Appearance, type AuthzDeclaration, type AuthzManifest, CboxIdFrontend, type FrontendClientOptions, type FrontendConfig, type FrontendConfigOptions, type FrontendSession, type LegacyUser, type LegacyVerifierOptions, type ManifestPermission, type ManifestPublisherConfig, type ManifestRole, type ManifestSyncSummary, type PasskeyOptions, type PermissionDefinition, type RoleDefinition, type SecondFactorKind, type SignInResult, type SmsCodeResult, type SocialProvider, buildManifest, challenge, createLegacyVerifier, createVerifier, defineAuthz, publishManifest, randomToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { A as AuthenticationError, C as CboxIdError, a as ConfigurationError, F as FrontendApiError, I as InvalidStateError } from './errors-D61xljZE.js';
|
|
2
|
-
export { a as CallbackParams, C as CboxIdClient, S as StoreSecretInput,
|
|
3
|
-
export { c as AuthorizationPrompt, b as AuthorizationRequest, A as AuthorizationRequestOptions, d as CboxActiveOrganization, e as CboxActor, a as CboxIdConfig, f as CboxOrganization, C as CboxUser, g as ClaimSource, D as DeviceAuthorization, h as DiscoveryDocument, O as OrganizationRole, R as RefreshedTokens, i as TokenResponse, T as TokenTypeHint, j as actor, k as
|
|
2
|
+
export { a as CallbackParams, C as CboxIdClient, P as PipeConnectOptions, b as PipeLeaseDeniedError, c as PipeLeaseError, d as PipeNotConnectedError, e as PipeProvider, f as PipeReauthorizationRequiredError, g as PipeTemporarilyUnavailableError, h as PipeToken, S as StoreSecretInput, i as StoredAuthState, V as VaultClient, j as VaultLease, k as VaultSecretRef, l as VerifyStandardWebhookOptions, m as VerifyWebhookOptions, W as WebhookHeaders, p as pipeConnectUrl, v as verifyStandardWebhook, n as verifyWebhook, w as withConnectReturn } from './client-xlEJalu8.js';
|
|
3
|
+
export { c as AuthorizationPrompt, b as AuthorizationRequest, A as AuthorizationRequestOptions, d as CboxActiveOrganization, e as CboxActor, a as CboxIdConfig, f as CboxOrganization, C as CboxUser, g as ClaimSource, D as DeviceAuthorization, h as DiscoveryDocument, F as FEATURE_FLAGS_SCOPE, O as OrganizationRole, R as RefreshedTokens, i as TokenResponse, T as TokenTypeHint, j as actor, k as featureFlags, l as hasFeature, m as hasPermission, n as hasRole, o as isSupportSession, p as organization, q as permissions, r as roles, s as sessionId } from './types-CC1bz68x.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The handler on YOUR side of a legacy migration.
|
|
@@ -130,9 +130,35 @@ interface FrontendConfig {
|
|
|
130
130
|
end_session: string;
|
|
131
131
|
jwks: string;
|
|
132
132
|
};
|
|
133
|
+
/**
|
|
134
|
+
* The social buttons to draw, exactly as the hosted sign-in page would: the environment's
|
|
135
|
+
* own providers, or — with `config({ organization })` — that organization's.
|
|
136
|
+
*/
|
|
133
137
|
social: SocialProvider[];
|
|
134
138
|
appearance?: Appearance;
|
|
139
|
+
/**
|
|
140
|
+
* Which other sign-in methods are switched on, so a box does not draw a button whose
|
|
141
|
+
* endpoint answers 403. Absent from instances that predate it.
|
|
142
|
+
*/
|
|
143
|
+
methods?: {
|
|
144
|
+
passkeys: boolean;
|
|
145
|
+
magic_link: boolean;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/** Options for {@link CboxIdFrontend.config}. */
|
|
149
|
+
interface FrontendConfigOptions {
|
|
150
|
+
/**
|
|
151
|
+
* The organization the box is for, by id or slug — the way a hosted page is addressed.
|
|
152
|
+
* `social` is then exactly what that organization's sign-in page offers. An organization
|
|
153
|
+
* the environment does not have is answered as no hint at all.
|
|
154
|
+
*/
|
|
155
|
+
organization?: string;
|
|
135
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* A second factor the person can answer an `mfa_required` with. Kinds only — the server
|
|
159
|
+
* never says which number a text would go to before one is sent.
|
|
160
|
+
*/
|
|
161
|
+
type SecondFactorKind = 'totp' | 'sms' | 'recovery_code';
|
|
136
162
|
/** What a sign-in attempt produced. */
|
|
137
163
|
type SignInResult = {
|
|
138
164
|
status: 'ok';
|
|
@@ -141,6 +167,11 @@ type SignInResult = {
|
|
|
141
167
|
} | {
|
|
142
168
|
status: 'mfa_required';
|
|
143
169
|
mfaToken: string;
|
|
170
|
+
/**
|
|
171
|
+
* The factors this person can answer with (laravel-id 1.24+). Absent when the
|
|
172
|
+
* instance predates the list — then only an authenticator or a recovery code works.
|
|
173
|
+
*/
|
|
174
|
+
factors?: SecondFactorKind[];
|
|
144
175
|
} | {
|
|
145
176
|
status: 'otp_required';
|
|
146
177
|
mfaToken: string;
|
|
@@ -152,6 +183,30 @@ type SignInResult = {
|
|
|
152
183
|
status: 'rate_limited';
|
|
153
184
|
retryAfter: number | undefined;
|
|
154
185
|
};
|
|
186
|
+
/** What asking for a texted sign-in code produced. */
|
|
187
|
+
type SmsCodeResult =
|
|
188
|
+
/** Sent. `to` is the number masked (`+45 ******78`); the code lasts `expiresIn` seconds. */
|
|
189
|
+
{
|
|
190
|
+
status: 'sent';
|
|
191
|
+
to: string;
|
|
192
|
+
expiresIn: number;
|
|
193
|
+
}
|
|
194
|
+
/** Too soon, or a sending limit was hit. Waiting `retryAfter` seconds may help. */
|
|
195
|
+
| {
|
|
196
|
+
status: 'rate_limited';
|
|
197
|
+
retryAfter: number | undefined;
|
|
198
|
+
}
|
|
199
|
+
/** The text provider failed. Try again shortly, or offer another factor. */
|
|
200
|
+
| {
|
|
201
|
+
status: 'unavailable';
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Refused: an unknown or spent token, no number on file, a country texts are not sent
|
|
205
|
+
* to, or no attempts left. One answer for every reason, like a wrong password.
|
|
206
|
+
*/
|
|
207
|
+
| {
|
|
208
|
+
status: 'invalid';
|
|
209
|
+
};
|
|
155
210
|
/** What a browser needs to ask an authenticator for a passkey assertion. */
|
|
156
211
|
interface PasskeyOptions {
|
|
157
212
|
challenge: string;
|
|
@@ -197,7 +252,7 @@ declare class CboxIdFrontend {
|
|
|
197
252
|
* fetches of the same immutable document is a waste the SDK should absorb rather than
|
|
198
253
|
* ask every consumer to.
|
|
199
254
|
*/
|
|
200
|
-
private
|
|
255
|
+
private readonly configPromises;
|
|
201
256
|
constructor(options: FrontendClientOptions);
|
|
202
257
|
/** Whether this key drives real sign-ins. Handy for a "test mode" badge in your own UI. */
|
|
203
258
|
get isLive(): boolean;
|
|
@@ -207,8 +262,9 @@ declare class CboxIdFrontend {
|
|
|
207
262
|
* Fetched once per client instance. The document is small and changes when somebody
|
|
208
263
|
* edits it in the console, so a long-lived page picks changes up on its next full load
|
|
209
264
|
* rather than mid-session — which is the right trade for something that decides layout.
|
|
265
|
+
* Each `organization` is fetched and cached on its own.
|
|
210
266
|
*/
|
|
211
|
-
config(): Promise<FrontendConfig>;
|
|
267
|
+
config(options?: FrontendConfigOptions): Promise<FrontendConfig>;
|
|
212
268
|
/**
|
|
213
269
|
* Who is signed in, given an access token your app already holds.
|
|
214
270
|
*
|
|
@@ -256,8 +312,29 @@ declare class CboxIdFrontend {
|
|
|
256
312
|
*
|
|
257
313
|
* A wrong code costs an attempt, not the sign-in: five are allowed before the token
|
|
258
314
|
* dies and the person starts from the password again.
|
|
315
|
+
*
|
|
316
|
+
* `method` says which challenge the code answers: `'mfa'` for an authenticator or
|
|
317
|
+
* recovery code, `'otp'` for an emailed code (`otp_required`), `'sms'` for a code sent
|
|
318
|
+
* with {@link sendSmsCode}. A texted code is six digits like an authenticator's, so the
|
|
319
|
+
* server cannot tell them apart by shape — answering one as the other is refused.
|
|
320
|
+
*/
|
|
321
|
+
submitSecondFactor(mfaToken: string, code: string, method?: 'mfa' | 'otp' | 'sms'): Promise<SignInResult>;
|
|
322
|
+
/**
|
|
323
|
+
* Text the person a sign-in code, when `mfa_required` listed `'sms'` in `factors`.
|
|
324
|
+
* Then finish with `submitSecondFactor(mfaToken, code, 'sms')`.
|
|
325
|
+
*
|
|
326
|
+
* Only call it when the person asks ("Text me a code"), never on page load: each send
|
|
327
|
+
* spends one of the token's five attempts — that is what bounds how many texts one
|
|
328
|
+
* proved password can cause — and every text costs the customer money.
|
|
329
|
+
*
|
|
330
|
+
* ```ts
|
|
331
|
+
* if (result.status === 'mfa_required' && result.factors?.includes('sms')) {
|
|
332
|
+
* const sent = await frontend.sendSmsCode(result.mfaToken)
|
|
333
|
+
* if (sent.status === 'sent') showCodeField(`We texted ${sent.to}`)
|
|
334
|
+
* }
|
|
335
|
+
* ```
|
|
259
336
|
*/
|
|
260
|
-
|
|
337
|
+
sendSmsCode(mfaToken: string): Promise<SmsCodeResult>;
|
|
261
338
|
/**
|
|
262
339
|
* The WebAuthn options for a passkey sign-in, and the handle that carries the challenge.
|
|
263
340
|
*
|
|
@@ -442,4 +519,4 @@ declare function buildManifest(declaration: AuthzDeclaration): Promise<AuthzMani
|
|
|
442
519
|
*/
|
|
443
520
|
declare function publishManifest(config: ManifestPublisherConfig, declaration: AuthzDeclaration): Promise<ManifestSyncSummary>;
|
|
444
521
|
|
|
445
|
-
export { type Appearance, type AuthzDeclaration, type AuthzManifest, CboxIdFrontend, type FrontendClientOptions, type FrontendConfig, type FrontendSession, type LegacyUser, type LegacyVerifierOptions, type ManifestPermission, type ManifestPublisherConfig, type ManifestRole, type ManifestSyncSummary, type PasskeyOptions, type PermissionDefinition, type RoleDefinition, type SignInResult, type SocialProvider, buildManifest, challenge, createLegacyVerifier, createVerifier, defineAuthz, publishManifest, randomToken };
|
|
522
|
+
export { type Appearance, type AuthzDeclaration, type AuthzManifest, CboxIdFrontend, type FrontendClientOptions, type FrontendConfig, type FrontendConfigOptions, type FrontendSession, type LegacyUser, type LegacyVerifierOptions, type ManifestPermission, type ManifestPublisherConfig, type ManifestRole, type ManifestSyncSummary, type PasskeyOptions, type PermissionDefinition, type RoleDefinition, type SecondFactorKind, type SignInResult, type SmsCodeResult, type SocialProvider, buildManifest, challenge, createLegacyVerifier, createVerifier, defineAuthz, publishManifest, randomToken };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Discovery } from './chunk-
|
|
2
|
-
export { CboxIdClient, VaultClient, actor, challenge, createVerifier, hasPermission, hasRole, isSupportSession, organization, permissions, randomToken, roles, sessionId, verifyStandardWebhook, verifyWebhook } from './chunk-
|
|
1
|
+
import { Discovery } from './chunk-YGLMLIKL.js';
|
|
2
|
+
export { CboxIdClient, FEATURE_FLAGS_SCOPE, PipeLeaseDeniedError, PipeLeaseError, PipeNotConnectedError, PipeReauthorizationRequiredError, PipeTemporarilyUnavailableError, VaultClient, actor, challenge, createVerifier, featureFlags, hasFeature, hasPermission, hasRole, isSupportSession, organization, permissions, pipeConnectUrl, randomToken, roles, sessionId, verifyStandardWebhook, verifyWebhook, withConnectReturn } from './chunk-YGLMLIKL.js';
|
|
3
3
|
import { assertSecureIssuer } from './chunk-QQW63PGU.js';
|
|
4
4
|
import { ConfigurationError, FrontendApiError, AuthenticationError } from './chunk-SEUD4TE4.js';
|
|
5
5
|
export { AuthenticationError, CboxIdError, ConfigurationError, FrontendApiError, InvalidStateError } from './chunk-SEUD4TE4.js';
|
|
@@ -98,6 +98,7 @@ function json(body, status) {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// src/frontend.ts
|
|
101
|
+
var SECOND_FACTOR_KINDS = /* @__PURE__ */ new Set(["totp", "sms", "recovery_code"]);
|
|
101
102
|
var CboxIdFrontend = class {
|
|
102
103
|
issuer;
|
|
103
104
|
publishableKey;
|
|
@@ -112,7 +113,7 @@ var CboxIdFrontend = class {
|
|
|
112
113
|
* fetches of the same immutable document is a waste the SDK should absorb rather than
|
|
113
114
|
* ask every consumer to.
|
|
114
115
|
*/
|
|
115
|
-
|
|
116
|
+
configPromises = /* @__PURE__ */ new Map();
|
|
116
117
|
constructor(options) {
|
|
117
118
|
if (!options.issuer) {
|
|
118
119
|
throw new ConfigurationError("issuer is required.");
|
|
@@ -139,13 +140,20 @@ var CboxIdFrontend = class {
|
|
|
139
140
|
* Fetched once per client instance. The document is small and changes when somebody
|
|
140
141
|
* edits it in the console, so a long-lived page picks changes up on its next full load
|
|
141
142
|
* rather than mid-session — which is the right trade for something that decides layout.
|
|
143
|
+
* Each `organization` is fetched and cached on its own.
|
|
142
144
|
*/
|
|
143
|
-
async config() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
async config(options = {}) {
|
|
146
|
+
const organization2 = options.organization ?? "";
|
|
147
|
+
let pending = this.configPromises.get(organization2);
|
|
148
|
+
if (pending === void 0) {
|
|
149
|
+
const path = organization2 === "" ? "/frontend/v1/config" : `/frontend/v1/config?${new URLSearchParams({ organization: organization2 }).toString()}`;
|
|
150
|
+
pending = this.get(path, {}, isFrontendConfig).catch((error) => {
|
|
151
|
+
this.configPromises.delete(organization2);
|
|
152
|
+
throw error;
|
|
153
|
+
});
|
|
154
|
+
this.configPromises.set(organization2, pending);
|
|
155
|
+
}
|
|
156
|
+
return pending;
|
|
149
157
|
}
|
|
150
158
|
/**
|
|
151
159
|
* Who is signed in, given an access token your app already holds.
|
|
@@ -207,8 +215,12 @@ var CboxIdFrontend = class {
|
|
|
207
215
|
if (body.status === "ok" && typeof body.login_ticket === "string") {
|
|
208
216
|
return { status: "ok", loginTicket: body.login_ticket, expiresIn: body.expires_in ?? 60 };
|
|
209
217
|
}
|
|
210
|
-
if (
|
|
211
|
-
|
|
218
|
+
if (body.status === "mfa_required" && typeof body.mfa_token === "string") {
|
|
219
|
+
const factors = Array.isArray(body.factors) ? body.factors.filter((f) => typeof f === "string" && SECOND_FACTOR_KINDS.has(f)) : void 0;
|
|
220
|
+
return { status: "mfa_required", mfaToken: body.mfa_token, ...factors ? { factors } : {} };
|
|
221
|
+
}
|
|
222
|
+
if (body.status === "otp_required" && typeof body.mfa_token === "string") {
|
|
223
|
+
return { status: "otp_required", mfaToken: body.mfa_token };
|
|
212
224
|
}
|
|
213
225
|
if (body.status === "sso_required") {
|
|
214
226
|
return { status: "sso_required" };
|
|
@@ -225,6 +237,11 @@ var CboxIdFrontend = class {
|
|
|
225
237
|
*
|
|
226
238
|
* A wrong code costs an attempt, not the sign-in: five are allowed before the token
|
|
227
239
|
* dies and the person starts from the password again.
|
|
240
|
+
*
|
|
241
|
+
* `method` says which challenge the code answers: `'mfa'` for an authenticator or
|
|
242
|
+
* recovery code, `'otp'` for an emailed code (`otp_required`), `'sms'` for a code sent
|
|
243
|
+
* with {@link sendSmsCode}. A texted code is six digits like an authenticator's, so the
|
|
244
|
+
* server cannot tell them apart by shape — answering one as the other is refused.
|
|
228
245
|
*/
|
|
229
246
|
async submitSecondFactor(mfaToken, code, method = "mfa") {
|
|
230
247
|
const response = await this.post("/frontend/v1/sign-in/factor", { mfa_token: mfaToken, code, method });
|
|
@@ -236,6 +253,41 @@ var CboxIdFrontend = class {
|
|
|
236
253
|
}
|
|
237
254
|
return body.status === "ok" && typeof body.login_ticket === "string" ? { status: "ok", loginTicket: body.login_ticket, expiresIn: body.expires_in ?? 60 } : { status: "invalid" };
|
|
238
255
|
}
|
|
256
|
+
/**
|
|
257
|
+
* Text the person a sign-in code, when `mfa_required` listed `'sms'` in `factors`.
|
|
258
|
+
* Then finish with `submitSecondFactor(mfaToken, code, 'sms')`.
|
|
259
|
+
*
|
|
260
|
+
* Only call it when the person asks ("Text me a code"), never on page load: each send
|
|
261
|
+
* spends one of the token's five attempts — that is what bounds how many texts one
|
|
262
|
+
* proved password can cause — and every text costs the customer money.
|
|
263
|
+
*
|
|
264
|
+
* ```ts
|
|
265
|
+
* if (result.status === 'mfa_required' && result.factors?.includes('sms')) {
|
|
266
|
+
* const sent = await frontend.sendSmsCode(result.mfaToken)
|
|
267
|
+
* if (sent.status === 'sent') showCodeField(`We texted ${sent.to}`)
|
|
268
|
+
* }
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
async sendSmsCode(mfaToken) {
|
|
272
|
+
const response = await this.post("/frontend/v1/sign-in/factor/sms", { mfa_token: mfaToken });
|
|
273
|
+
let body;
|
|
274
|
+
try {
|
|
275
|
+
body = await response.json();
|
|
276
|
+
} catch {
|
|
277
|
+
throw new FrontendApiError("Cbox ID returned a body that is not JSON.", "malformed", response.status);
|
|
278
|
+
}
|
|
279
|
+
if (body.status === "sent" && typeof body.to === "string") {
|
|
280
|
+
return { status: "sent", to: body.to, expiresIn: typeof body.expires_in === "number" ? body.expires_in : 300 };
|
|
281
|
+
}
|
|
282
|
+
if (body.status === "rate_limited" || response.status === 429) {
|
|
283
|
+
const retryAfter = typeof body.retry_after === "number" ? body.retry_after : Number(response.headers.get("Retry-After") ?? "");
|
|
284
|
+
return { status: "rate_limited", retryAfter: Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter : void 0 };
|
|
285
|
+
}
|
|
286
|
+
if (body.status === "unavailable") {
|
|
287
|
+
return { status: "unavailable" };
|
|
288
|
+
}
|
|
289
|
+
return { status: "invalid" };
|
|
290
|
+
}
|
|
239
291
|
/**
|
|
240
292
|
* The WebAuthn options for a passkey sign-in, and the handle that carries the challenge.
|
|
241
293
|
*
|