@base44-preview/sdk 0.8.52-pr.298.d08e0ba → 0.8.52-pr.299.9f7108e
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 +0 -2
- package/dist/client.js +2 -0
- package/dist/client.types.d.ts +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/modules/auth.js +6 -13
- package/dist/modules/auth.types.d.ts +3 -7
- package/dist/modules/mcp.d.ts +11 -0
- package/dist/modules/mcp.js +20 -0
- package/dist/modules/mcp.types.d.ts +101 -0
- package/dist/modules/mcp.types.js +1 -0
- package/package.json +1 -1
- package/dist/modules/mfa.d.ts +0 -52
- package/dist/modules/mfa.js +0 -43
package/README.md
CHANGED
package/dist/client.js
CHANGED
|
@@ -11,6 +11,7 @@ import { createAgentsModule } from "./modules/agents.js";
|
|
|
11
11
|
import { createAiGatewayModule } from "./modules/ai-gateway.js";
|
|
12
12
|
import { createAppLogsModule } from "./modules/app-logs.js";
|
|
13
13
|
import { createAppModule } from "./modules/app.js";
|
|
14
|
+
import { createMcpModule } from "./modules/mcp.js";
|
|
14
15
|
import { createUsersModule } from "./modules/users.js";
|
|
15
16
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
16
17
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
@@ -201,6 +202,7 @@ export function createClient(config) {
|
|
|
201
202
|
}),
|
|
202
203
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
203
204
|
app: createAppModule(axiosClient, appId),
|
|
205
|
+
mcp: createMcpModule(axiosClient, appId),
|
|
204
206
|
users: createUsersModule(axiosClient, appId),
|
|
205
207
|
analytics: createAnalyticsModule({
|
|
206
208
|
axiosClient,
|
package/dist/client.types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { AgentsModule } from "./modules/agents.types.js";
|
|
|
8
8
|
import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
|
|
9
9
|
import type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
10
10
|
import type { AppModule } from "./modules/app.types.js";
|
|
11
|
+
import type { McpModule } from "./modules/mcp.types.js";
|
|
11
12
|
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
12
13
|
import type { ActorsModule } from "./modules/actors.types.js";
|
|
13
14
|
import type { FetchWithAuthInit } from "./utils/fetch-with-auth.js";
|
|
@@ -138,6 +139,8 @@ export interface Base44Client {
|
|
|
138
139
|
functions: FunctionsModule;
|
|
139
140
|
/** {@link IntegrationsModule | Integrations module} for calling pre-built integration endpoints. */
|
|
140
141
|
integrations: IntegrationsModule;
|
|
142
|
+
/** {@link McpModule | MCP module} for the app's MCP consent page. */
|
|
143
|
+
mcp: McpModule;
|
|
141
144
|
/** Cleanup function to disconnect WebSocket connections. Call when you're done with the client. */
|
|
142
145
|
cleanup: () => void;
|
|
143
146
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -12,10 +12,10 @@ export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, Age
|
|
|
12
12
|
export type { AiGatewayModule, AiGatewayConnection, AiGatewayConnectionOptions, } from "./modules/ai-gateway.types.js";
|
|
13
13
|
export type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
14
14
|
export type { AppModule, AppPublicSettings, AppPublicSettingsResponse, } from "./modules/app.types.js";
|
|
15
|
+
export type { McpModule, McpConsentInfo, McpConsentTool, McpConsentAction, McpAuthorizeGrantResponse, } from "./modules/mcp.types.js";
|
|
15
16
|
export type { ActorsModule, ActorClient, ActorRef, Connection, ActorSubscription, ActorConnectOptions, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
|
|
16
17
|
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
|
|
17
18
|
export { Actor, type Conn } from "./actor.js";
|
|
18
19
|
export type { ConnectorsModule, UserConnectorsModule, ConnectorApiRequest, ConnectorApiResponse, ConnectorApiResponsePhase, } from "./modules/connectors.types.js";
|
|
19
20
|
export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
|
|
20
21
|
export type { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions, } from "./utils/auth-utils.types.js";
|
|
21
|
-
export type { MfaChallenge, MfaModule, MfaProof, LoginResult, MfaEnrollmentResult } from "./modules/mfa.js";
|
package/dist/modules/auth.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createMfaModule, prepareMfaPkce } from "./mfa.js";
|
|
2
1
|
import { resetAnalyticsSessionContext } from "./analytics.js";
|
|
3
2
|
function isInsideIframe() {
|
|
4
3
|
if (typeof window === "undefined")
|
|
@@ -20,9 +19,9 @@ function loginViaPopup(url, redirectUrl, expectedOrigin) {
|
|
|
20
19
|
const height = 600;
|
|
21
20
|
const left = Math.round(window.screenX + (window.outerWidth - width) / 2);
|
|
22
21
|
const top = Math.round(window.screenY + (window.outerHeight - height) / 2);
|
|
23
|
-
const popup = window.open(
|
|
22
|
+
const popup = window.open(url, "base44_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`);
|
|
24
23
|
if (!popup) {
|
|
25
|
-
return
|
|
24
|
+
return;
|
|
26
25
|
}
|
|
27
26
|
const cleanup = () => {
|
|
28
27
|
window.removeEventListener("message", onMessage);
|
|
@@ -53,7 +52,6 @@ function loginViaPopup(url, redirectUrl, expectedOrigin) {
|
|
|
53
52
|
cleanup();
|
|
54
53
|
}, 500);
|
|
55
54
|
window.addEventListener("message", onMessage);
|
|
56
|
-
return url.then(value => { popup.location.href = value; }, error => { cleanup(); throw error; });
|
|
57
55
|
}
|
|
58
56
|
/**
|
|
59
57
|
* Creates the auth module for the Base44 SDK.
|
|
@@ -84,8 +82,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
84
82
|
// to the identity transitions below (`setToken`, `logout`) instead of to the
|
|
85
83
|
// header a caller may have set on the instance directly.
|
|
86
84
|
let hasAccessToken = Boolean(options.token);
|
|
87
|
-
|
|
88
|
-
mfa: createMfaModule(axios, appId, token => module.setToken(token)),
|
|
85
|
+
return {
|
|
89
86
|
hasToken() {
|
|
90
87
|
return hasAccessToken;
|
|
91
88
|
},
|
|
@@ -122,10 +119,9 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
122
119
|
window.location.href = loginUrl;
|
|
123
120
|
},
|
|
124
121
|
// Redirects the user to a provider's login page
|
|
125
|
-
|
|
122
|
+
loginWithProvider(provider, fromUrl = "/") {
|
|
126
123
|
// Build the full redirect URL
|
|
127
124
|
const redirectUrl = new URL(fromUrl, window.location.origin).toString();
|
|
128
|
-
const mfaPkce = provider === "sso" ? Promise.resolve("") : prepareMfaPkce(appId).then(value => `&app_mfa_code_challenge=${value}`);
|
|
129
125
|
const queryParams = `app_id=${appId}&from_url=${encodeURIComponent(redirectUrl)}`;
|
|
130
126
|
// SSO uses a different URL structure with appId in the path
|
|
131
127
|
let authPath;
|
|
@@ -141,11 +137,11 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
141
137
|
// When running inside an iframe, use a popup to avoid OAuth providers
|
|
142
138
|
// blocking iframe navigation.
|
|
143
139
|
if (isInsideIframe()) {
|
|
144
|
-
const popupLoginUrl =
|
|
140
|
+
const popupLoginUrl = `${loginUrl}&popup_origin=${encodeURIComponent(window.location.origin)}`;
|
|
145
141
|
return loginViaPopup(popupLoginUrl, redirectUrl, window.location.origin);
|
|
146
142
|
}
|
|
147
143
|
// Default: full-page redirect
|
|
148
|
-
window.location.href = loginUrl
|
|
144
|
+
window.location.href = loginUrl;
|
|
149
145
|
},
|
|
150
146
|
// Logout the current user
|
|
151
147
|
logout(redirectUrl) {
|
|
@@ -211,8 +207,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
211
207
|
password,
|
|
212
208
|
...(turnstileToken && { turnstile_token: turnstileToken }),
|
|
213
209
|
});
|
|
214
|
-
if (response.mfa_required)
|
|
215
|
-
return response;
|
|
216
210
|
const { access_token, user } = response;
|
|
217
211
|
if (access_token) {
|
|
218
212
|
this.setToken(access_token);
|
|
@@ -284,5 +278,4 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
284
278
|
});
|
|
285
279
|
},
|
|
286
280
|
};
|
|
287
|
-
return module;
|
|
288
281
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { LoginResult, MfaModule } from "./mfa.js";
|
|
2
1
|
/**
|
|
3
2
|
* An authenticated user.
|
|
4
3
|
*/
|
|
@@ -38,7 +37,6 @@ export interface User {
|
|
|
38
37
|
* Response from login endpoints containing user information and access token.
|
|
39
38
|
*/
|
|
40
39
|
export interface LoginResponse {
|
|
41
|
-
mfa_required?: false;
|
|
42
40
|
/** JWT access token for authentication. */
|
|
43
41
|
access_token: string;
|
|
44
42
|
/** User information. */
|
|
@@ -119,8 +117,6 @@ export interface AuthModuleOptions {
|
|
|
119
117
|
* The auth module is only available in user authentication mode (`base44.auth`).
|
|
120
118
|
*/
|
|
121
119
|
export interface AuthModule {
|
|
122
|
-
/** Multi-factor enrollment and login for this app. */
|
|
123
|
-
mfa: MfaModule;
|
|
124
120
|
/**
|
|
125
121
|
* Gets the current authenticated user's information.
|
|
126
122
|
*
|
|
@@ -223,7 +219,7 @@ export interface AuthModule {
|
|
|
223
219
|
* ```
|
|
224
220
|
*
|
|
225
221
|
*/
|
|
226
|
-
loginWithProvider(provider: string, fromUrl?: string):
|
|
222
|
+
loginWithProvider(provider: string, fromUrl?: string): void;
|
|
227
223
|
/**
|
|
228
224
|
* Logs out the current user.
|
|
229
225
|
*
|
|
@@ -306,7 +302,7 @@ export interface AuthModule {
|
|
|
306
302
|
* );
|
|
307
303
|
* ```
|
|
308
304
|
*/
|
|
309
|
-
loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<
|
|
305
|
+
loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<LoginResponse>;
|
|
310
306
|
/**
|
|
311
307
|
* Checks if the current user is authenticated.
|
|
312
308
|
*
|
|
@@ -431,7 +427,7 @@ export interface AuthModule {
|
|
|
431
427
|
* );
|
|
432
428
|
* ```
|
|
433
429
|
*/
|
|
434
|
-
verifyOtp(params: VerifyOtpParams): Promise<
|
|
430
|
+
verifyOtp(params: VerifyOtpParams): Promise<any>;
|
|
435
431
|
/**
|
|
436
432
|
* Resends an OTP code to the user's email address.
|
|
437
433
|
*
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
import { McpModule } from "./mcp.types";
|
|
3
|
+
/**
|
|
4
|
+
* Creates the MCP module for the Base44 SDK.
|
|
5
|
+
*
|
|
6
|
+
* @param axios - Axios instance
|
|
7
|
+
* @param appId - Application ID
|
|
8
|
+
* @returns MCP module for the app's MCP consent page
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function createMcpModule(axios: AxiosInstance, appId: string): McpModule;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates the MCP module for the Base44 SDK.
|
|
3
|
+
*
|
|
4
|
+
* @param axios - Axios instance
|
|
5
|
+
* @param appId - Application ID
|
|
6
|
+
* @returns MCP module for the app's MCP consent page
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export function createMcpModule(axios, appId) {
|
|
10
|
+
return {
|
|
11
|
+
async getConsentInfo(ctx) {
|
|
12
|
+
return axios.get(`/apps/${appId}/mcp/consent-info`, {
|
|
13
|
+
params: { handle: ctx },
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
async authorizeGrant(ctx, action) {
|
|
17
|
+
return axios.post(`/apps/${appId}/mcp/authorize-grant`, { ctx, action });
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One tool shown on the MCP consent page.
|
|
3
|
+
*/
|
|
4
|
+
export interface McpConsentTool {
|
|
5
|
+
/** The tool's MCP name. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Human-readable title, when the tool has one. */
|
|
8
|
+
title?: string | null;
|
|
9
|
+
/** What the tool does. */
|
|
10
|
+
description?: string | null;
|
|
11
|
+
/** Whether the tool only reads data. */
|
|
12
|
+
read_only_hint?: boolean | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Display details for a pending MCP authorization request, as returned by
|
|
16
|
+
* {@link McpModule.getConsentInfo}.
|
|
17
|
+
*/
|
|
18
|
+
export interface McpConsentInfo {
|
|
19
|
+
/** The app's display name. */
|
|
20
|
+
app_name: string;
|
|
21
|
+
/** The name of the AI client asking for access. */
|
|
22
|
+
client_name: string;
|
|
23
|
+
/**
|
|
24
|
+
* Whether the request came from a signed-in user of this app. When `false`,
|
|
25
|
+
* send the user to `login_path` before showing approve and deny.
|
|
26
|
+
*/
|
|
27
|
+
authenticated: boolean;
|
|
28
|
+
/** The tools the client will be able to use. Empty unless `authenticated` is `true`. */
|
|
29
|
+
tools: McpConsentTool[];
|
|
30
|
+
/** The app's login route for a signed-out user, such as `/login`. */
|
|
31
|
+
login_path: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The user's decision on an MCP authorization request.
|
|
35
|
+
*/
|
|
36
|
+
export type McpConsentAction = "approve" | "deny";
|
|
37
|
+
/**
|
|
38
|
+
* Result of {@link McpModule.authorizeGrant}.
|
|
39
|
+
*/
|
|
40
|
+
export interface McpAuthorizeGrantResponse {
|
|
41
|
+
/**
|
|
42
|
+
* Where to send the browser next: the AI client's redirect URI, carrying the
|
|
43
|
+
* authorization code on approve or an `access_denied` error on deny. It may
|
|
44
|
+
* use a custom scheme such as `cursor://`.
|
|
45
|
+
*/
|
|
46
|
+
redirect_url: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* MCP module for the app's MCP consent page.
|
|
50
|
+
*
|
|
51
|
+
* When an AI client connects to the app's MCP server, Base44 sends the user to
|
|
52
|
+
* the app's consent page with an opaque `ctx` query parameter. The page reads
|
|
53
|
+
* the request's details with {@link McpModule.getConsentInfo | getConsentInfo()}
|
|
54
|
+
* and records the user's decision with {@link McpModule.authorizeGrant | authorizeGrant()}.
|
|
55
|
+
*
|
|
56
|
+
* ## Authentication Modes
|
|
57
|
+
*
|
|
58
|
+
* This module is available to use with a client in user authentication mode. The
|
|
59
|
+
* signed-in user's token is sent when the client has one; otherwise the app's
|
|
60
|
+
* session cookie identifies the user.
|
|
61
|
+
*/
|
|
62
|
+
export interface McpModule {
|
|
63
|
+
/**
|
|
64
|
+
* Gets the display details for a pending MCP authorization request.
|
|
65
|
+
*
|
|
66
|
+
* Rejects with a {@linkcode Base44Error} with `status` `404` when the `ctx`
|
|
67
|
+
* handle is unknown or expired.
|
|
68
|
+
*
|
|
69
|
+
* @param ctx - The `ctx` query parameter the consent page was opened with.
|
|
70
|
+
* @returns Promise resolving to the request's display details.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const ctx = new URLSearchParams(window.location.search).get('ctx');
|
|
75
|
+
* const info = await base44.mcp.getConsentInfo(ctx);
|
|
76
|
+
* if (!info.authenticated) {
|
|
77
|
+
* window.location.href = info.login_path;
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
getConsentInfo(ctx: string): Promise<McpConsentInfo>;
|
|
82
|
+
/**
|
|
83
|
+
* Records the signed-in user's decision on an MCP authorization request.
|
|
84
|
+
*
|
|
85
|
+
* The `ctx` handle is single-use. Rejects with a {@linkcode Base44Error}:
|
|
86
|
+
* `status` `401` when the user must sign in again (the handle is still valid),
|
|
87
|
+
* and `400`, `403`, `404` or `409` when the request can no longer be
|
|
88
|
+
* completed and the user must reconnect from the AI client.
|
|
89
|
+
*
|
|
90
|
+
* @param ctx - The `ctx` query parameter the consent page was opened with.
|
|
91
|
+
* @param action - `"approve"` to grant access, `"deny"` to refuse it.
|
|
92
|
+
* @returns Promise resolving to the URL to send the browser to.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const { redirect_url } = await base44.mcp.authorizeGrant(ctx, 'approve');
|
|
97
|
+
* window.location.href = redirect_url;
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
authorizeGrant(ctx: string, action: McpConsentAction): Promise<McpAuthorizeGrantResponse>;
|
|
101
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
package/dist/modules/mfa.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import type { AxiosInstance } from 'axios';
|
|
2
|
-
import type { LoginResponse } from './auth.types.js';
|
|
3
|
-
/** A restricted, short-lived login outcome. It is never an access token. */
|
|
4
|
-
export interface MfaChallenge {
|
|
5
|
-
mfa_required: true;
|
|
6
|
-
next_step: 'enroll' | 'verify';
|
|
7
|
-
mfa_methods: ('totp' | 'sms')[];
|
|
8
|
-
mfa_session_token: string;
|
|
9
|
-
expires_in_seconds: number;
|
|
10
|
-
phone_hint?: string;
|
|
11
|
-
access_token?: never;
|
|
12
|
-
user?: never;
|
|
13
|
-
}
|
|
14
|
-
export type LoginResult = LoginResponse | MfaChallenge;
|
|
15
|
-
export interface MfaEnrollmentResult extends LoginResponse {
|
|
16
|
-
backup_codes?: string[];
|
|
17
|
-
}
|
|
18
|
-
export interface MfaProof {
|
|
19
|
-
code: string;
|
|
20
|
-
method: 'totp' | 'sms';
|
|
21
|
-
remember_device?: boolean;
|
|
22
|
-
}
|
|
23
|
-
/** App-scoped MFA. Pass the challenge credential explicitly; do not set it as the SDK token. */
|
|
24
|
-
export interface MfaModule {
|
|
25
|
-
getStatus(): Promise<{
|
|
26
|
-
mfa_enabled: boolean;
|
|
27
|
-
methods: ('totp' | 'sms')[];
|
|
28
|
-
backup_codes_remaining: number;
|
|
29
|
-
policy: 'off' | 'required';
|
|
30
|
-
}>;
|
|
31
|
-
/** Requires an app admin session; resets a user in this app only. */
|
|
32
|
-
resetForUser(appUserId: string): Promise<{
|
|
33
|
-
success: true;
|
|
34
|
-
}>;
|
|
35
|
-
/** Open managed settings with fresh primary authentication and factor verification. */
|
|
36
|
-
openSecurity(returnTo?: string): void;
|
|
37
|
-
setupTotp(challenge: MfaChallenge): Promise<{
|
|
38
|
-
secret: string;
|
|
39
|
-
secret_formatted: string;
|
|
40
|
-
qr_code: string;
|
|
41
|
-
}>;
|
|
42
|
-
sendSms(challenge: MfaChallenge, phoneNumber: string): Promise<unknown>;
|
|
43
|
-
enrollTotp(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<MfaEnrollmentResult>;
|
|
44
|
-
enrollSms(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<MfaEnrollmentResult>;
|
|
45
|
-
verify(challenge: MfaChallenge, proof: MfaProof): Promise<LoginResponse>;
|
|
46
|
-
verifyRecoveryCode(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<LoginResponse>;
|
|
47
|
-
resendSms(challenge: MfaChallenge): Promise<unknown>;
|
|
48
|
-
/** Open Base44's managed MFA flow on this app's origin. */
|
|
49
|
-
continueLogin(challenge: MfaChallenge, returnTo?: string): Promise<void>;
|
|
50
|
-
}
|
|
51
|
-
export declare function prepareMfaPkce(appId: string): Promise<string>;
|
|
52
|
-
export declare function createMfaModule(axios: AxiosInstance, appId: string, setToken: (token: string) => void): MfaModule;
|
package/dist/modules/mfa.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export async function prepareMfaPkce(appId) {
|
|
2
|
-
const encode = (value) => btoa(String.fromCharCode(...value)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
3
|
-
const verifier = encode(crypto.getRandomValues(new Uint8Array(32)));
|
|
4
|
-
sessionStorage.setItem(`app-mfa-pkce:${appId}`, verifier);
|
|
5
|
-
return encode(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))));
|
|
6
|
-
}
|
|
7
|
-
export function createMfaModule(axios, appId, setToken) {
|
|
8
|
-
const post = async (challenge, path, payload = {}) => {
|
|
9
|
-
const response = await axios.post(`/apps/${appId}/auth/mfa${path}`, payload, {
|
|
10
|
-
headers: { Authorization: `Bearer ${challenge.mfa_session_token}` }, withCredentials: true,
|
|
11
|
-
});
|
|
12
|
-
const token = response.access_token;
|
|
13
|
-
if (token)
|
|
14
|
-
setToken(token);
|
|
15
|
-
return response;
|
|
16
|
-
};
|
|
17
|
-
return {
|
|
18
|
-
getStatus: () => axios.get(`/apps/${appId}/auth/mfa/status`),
|
|
19
|
-
resetForUser: appUserId => axios.post(`/apps/${appId}/auth/mfa/reset`, { app_user_id: appUserId }),
|
|
20
|
-
openSecurity(returnTo = '/') {
|
|
21
|
-
const target = new URL(returnTo, window.location.origin);
|
|
22
|
-
if (target.origin !== window.location.origin)
|
|
23
|
-
throw new Error('MFA must return to this app.');
|
|
24
|
-
window.location.href = `/auth/mfa?${new URLSearchParams({ security: '1', from_url: target.pathname + target.search + target.hash })}`;
|
|
25
|
-
},
|
|
26
|
-
setupTotp: challenge => post(challenge, '/totp/setup'),
|
|
27
|
-
sendSms: (challenge, phoneNumber) => post(challenge, '/sms/send-code', { phone_number: phoneNumber }),
|
|
28
|
-
enrollTotp: (challenge, code, rememberDevice = false) => post(challenge, '/totp/verify', { code, remember_device: rememberDevice }),
|
|
29
|
-
enrollSms: (challenge, code, rememberDevice = false) => post(challenge, '/sms/verify', { code, remember_device: rememberDevice }),
|
|
30
|
-
verify: (challenge, proof) => post(challenge, '/verify', proof),
|
|
31
|
-
verifyRecoveryCode: (challenge, code, rememberDevice = false) => post(challenge, '/verify-backup', { backup_code: code, remember_device: rememberDevice }),
|
|
32
|
-
resendSms: challenge => post(challenge, '/resend'),
|
|
33
|
-
async continueLogin(challenge, returnTo = '/') {
|
|
34
|
-
const target = new URL(returnTo, window.location.origin);
|
|
35
|
-
if (target.origin !== window.location.origin)
|
|
36
|
-
throw new Error('MFA must return to this app.');
|
|
37
|
-
const codeChallenge = await prepareMfaPkce(appId);
|
|
38
|
-
const handoff = await post(challenge, '/handoff', { code_challenge: codeChallenge });
|
|
39
|
-
const query = new URLSearchParams({ app_id: appId, mfa_code: handoff.code, from_url: target.pathname + target.search + target.hash });
|
|
40
|
-
window.location.href = `/auth/mfa?${query}`;
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
}
|