You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 114885e
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: adminforth/documentation/docs/tutorial/09-Plugins/02-TwoFactorsAuth.md
+34-12Lines changed: 34 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -276,14 +276,24 @@ Here is an example:
276
276
277
277
Under the hood, this metod uses websocket.
278
278
279
+
To tell the user what they confirm, pass a short description of the action as the second argument:
280
+
281
+
```ts
282
+
const verifyResult =awaitt2fa.verifyAuto(adminUser, `Approve a $${amount} bonus for ${employee.name}`);
283
+
```
284
+
285
+
The 2FA modal shows the description above the authenticator code field. When an AI agent runs the action through the [MCP server](/docs/tutorial/Plugins/mcp/), the confirmation page in the admin panel shows the description instead of the raw arguments of the agent's call.
286
+
287
+
`verifyAuto` also works in a tool call of the MCP server. There is no browser tab to show the modal in, so a missing verification stops the whole call, and the agent gets a link to [confirm the action in the admin panel](/docs/tutorial/Plugins/mcp/#actions-that-require-2fa), where the action runs again. Call `verifyAuto` before the action changes anything, otherwise the changes made before it happen twice.
288
+
279
289
## Manual Step-Up MFA (Two-Factor re-authentication on critical operations)
280
290
But if you websocket doesn't work in you application, or you wan't to perform verification manually, here are manual verification examples
281
291
282
292
### Request 2FA on custom Actions
283
293
284
294
You might want to to allow to call some custom critical/money related actions with additional 2FA approval. This eliminates risks caused by user cookies theft by some virous/doorway software after login.
285
295
286
-
To do it, first, create frontend custom component which wraps and intercepts click event to menu item, and in click handler do a call to `get2FaConfirmationResult` frontend API exposed by this plugin. This is awaitable call wich shows 2FA popup and asks user to authenticate with 2nd factor (if passkey is enabled it will be suggested first, with ability to fallback to TOTP)
296
+
To do it, first, create frontend custom component which wraps and intercepts click event to menu item, and in click handler do a call to `get2FaConfirmationResult` frontend API exposed by this plugin. This is awaitable call wich shows 2FA popup and asks user to authenticate with 2nd factor (if passkey is enabled it will be suggested first, with ability to fallback to TOTP). The popup checks the TOTP code and stays open until the user enters a correct code or closes it. Instead of the code, it returns a token that confirms the checked code for 1 minute, so `verify` does not check the code a second time.
Pass the verification result to `t2fa.verify` as is, even when the action was called without it, and return the `code` of a failed verification together with the error. `verify` lets users excluded by `usersFilterToApply` and users in the [grace period](#step-up-authentication-grace-period) through without a verification result, and returns the `TWO_FACTOR_REQUIRED` code for everyone else, so callers such as AI agents can tell that the action needs a second factor. The [MCP server](/docs/tutorial/Plugins/mcp/#actions-that-require-2fa) then lets the user confirm the action in the admin panel.
386
+
387
+
### Verification error codes
388
+
389
+
A failed `verify` returns `{ error, code }`, and a failed `verifyAuto` returns `{ ok: false, error, code }`. In a tool call of the MCP server a failed `verifyAuto` does not return: it stops the call, and the agent gets the error. The `code` is one of `TwoFactorErrorCode`, exported by the plugin:
390
+
391
+
| Code | Meaning |
392
+
|------|---------|
393
+
| `TWO_FACTOR_REQUIRED` | No verification result was passed, and the user is not excluded from 2FA or in the grace period. |
394
+
| `TWO_FACTOR_INVALID` | The TOTP code is wrong or expired, the code confirmation returned by the popup expired, or the passkey is invalid. |
395
+
| `TWO_FACTOR_RATE_LIMITED` | The user entered TOTP codes too often. Every TOTP check, at login and for step-up verification, counts as an attempt, and a user gets 30 attempts per minute, 300 per hour and 1000 per day. |
396
+
| `TWO_FACTOR_NOT_SET_UP` | The user has not set up 2FA yet. |
397
+
| `USER_NOT_FOUND` | The user no longer exists. |
398
+
| `UNSUPPORTED_CONFIRMATION_MODE` | The verification result has an unknown `mode`. |
399
+
| `BROWSER_CONTEXT_REQUIRED` | `verifyAuto` was called outside a browser request and outside a tool call of the MCP server, so there is no browser tab to show the modal in. |
400
+
| `VERIFICATION_CANCELLED` | The user closed the modal opened by `verifyAuto`. |
401
+
| `VERIFICATION_TIMEOUT` | The user did not answer the modal opened by `verifyAuto` within 5 minutes. |
402
+
| `INVALID_VERIFICATION_SESSION` | The modal answered a `verifyAuto` session that is invalid or belongs to another user. |
403
+
| `INTERNAL_ERROR` | The verification failed with an unexpected error. |
404
+
383
405
### Request 2FA for create/edit (secure save gating)
384
406
385
407
To protect create and edit operations, use a Save Interceptor injected on the page to gate the save with 2FA, and forward the result to the backend for verification. This avoids wrapping the Save button and works with the default UI.
Copy file name to clipboardExpand all lines: adminforth/documentation/docs/tutorial/09-Plugins/30-mcp.md
+47-1Lines changed: 47 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -240,7 +240,7 @@ The same numbers are quoted in the instructions and skills the MCP server gives
240
240
241
241
A tool call fails with a timeout error when its handler runs longer than `toolTimeoutMs`, 15 seconds by default. The handler gets an aborted signal, and the error tells the agent that a change it started may still complete, so it checks the result before calling again.
242
242
243
-
The instructions also ask the agent to make at most `toolCallsPerRequest` calls, 10 by default, for one user request, and to ask the user before it continues with more. MCP clients do not tell the server where a user request starts, so this is guidance for the agent, not a limit the server enforces.
243
+
The instructions also ask the agent to make at most `toolCallsPerRequest` calls, 10 by default, for one user request, and to ask the user before it continues with more. Calls of `wait_for_confirmation`, which waits for an [action confirmed in the admin panel](#actions-that-require-2fa), do not count. MCP clients do not tell the server where a user request starts, so this is guidance for the agent, not a limit the server enforces.
244
244
245
245
```ts title="./index.ts"
246
246
newAdminForthMcpPlugin({
@@ -260,6 +260,41 @@ The MCP server sends agents short rules in its instructions: to treat record val
260
260
261
261
Tools that change data, such as `delete_record`, are marked as destructive for MCP clients, and their descriptions repeat that the agent must get a confirmation in chat, even when the client itself does not ask for approval.
262
262
263
+
## Actions that require 2FA
264
+
265
+
With the [Two-Factor Authentication plugin](/docs/tutorial/Plugins/two-factors-auth/) installed, agents can run actions protected with a second factor: the user confirms such an action in the admin panel. The action asks for the second factor with [`verifyAuto`](/docs/tutorial/Plugins/two-factors-auth/#calling-2fa-modal-from-backend) or [`verify`](/docs/tutorial/Plugins/two-factors-auth/#request-2fa-on-custom-actions) and returns the `code` of a failed verification:
An agent's call has no second factor, so the action fails with the `TWO_FACTOR_REQUIRED` code. Then:
280
+
281
+
1. Instead of the error, the agent gets a `confirmationUrl` to a page of the admin panel and a `confirmationId`.
282
+
2. The agent shows the link to the user and calls the `wait_for_confirmation` tool with the `confirmationId`. The tool returns a waiting status after about 50 seconds, and the agent calls it again to keep waiting.
283
+
3. The user opens the link, signed in to the admin panel, and clicks **Confirm** or **Decline**. The page shows the description passed to `verifyAuto`, or, without one, the tool and the arguments of the agent's call. **Confirm** asks for the second factor.
284
+
4. The admin panel runs the action again with the user's verification, and `wait_for_confirmation` returns its result. If the user declines, the agent gets an error.
285
+
286
+
A confirmation link:
287
+
288
+
- opens only for the user who owns the MCP connection, and only this connection can wait for its result;
289
+
- expires after 10 minutes and works once: a wrong code or a closed 2FA modal ends it, and the agent has to call the action again;
290
+
- runs the action with the same [tool timeout](#tool-timeout-and-call-limit).
291
+
292
+
The admin panel runs the whole call again, so ask for the second factor before the action changes anything. Otherwise the changes made before the check happen twice.
293
+
294
+
Pending confirmations are kept in the memory of the server process. If the admin panel runs on several instances, a link works only when the page request reaches the instance that served the agent's call.
295
+
296
+
Without the Two-Factor Authentication plugin, the server has no `wait_for_confirmation` tool and no confirmation page.
297
+
263
298
## Tool responses
264
299
265
300
Tool responses are trimmed to save the agent's context:
@@ -281,6 +316,17 @@ new AdminForthMcpPlugin({
281
316
}),
282
317
```
283
318
319
+
To make only some users' connections read-only, pass a function of the user instead, as in [`allowedActions`](/docs/tutorial/Customization/limitingAccess/). It may be async. The function is called on every MCP request, so a user it starts returning `true` for loses write access from the next request. It also locks the **Read only** checkbox for that user in **MCP Settings** and on the consent page:
A connection is read-only when either the option or its stored `read_only` value says so.
329
+
284
330
In read-only mode the server exposes only endpoints marked with `agent: { onlyReadsData: true }`, such as `get_resource`, `get_resource_data`, and `aggregate`. Creating, updating, and deleting records and running actions are not available. To make your own endpoint available in read-only mode, mark it with `onlyReadsData: true`.
0 commit comments