What an authenticator code is, and why agents get stuck on it
An authenticator app turns a shared secret, the TOTP seed, into a six digit code that changes every 30 seconds (RFC 6238) [3]. The site shows the seed once, as a QR code or a setup key. Without the seed, an agent that reaches the code prompt has to stop and wait for a person with the phone. Use the seed for the agent's own seat, not the one on your own login.
Option 1: generate the code in your own code
otplib is an open source library for one time passwords (HOTP and TOTP) in Node.js and the browser [1]. Your Playwright or Stagehand code computes the current code from the seed and types it into the field. It works, and the seed then lives in your code or its environment, so treat that like a password file.
Option 2: framework features
Browser Use takes the TOTP secret in sensitive_data under a key that ends in bu_2fa_code. When the agent enters that placeholder, Browser Use generates a fresh six digit code [2]. For codes sent by email or SMS, its docs use follow up tasks, and show AgentMail inboxes for email [2].
Browserbase's MFA handling template generates TOTP codes with the RFC 6238 algorithm (HMAC-SHA1, 30 second windows) and types them with Stagehand [3]. Its authentication docs also suggest taking remote control with Session Live View, so a person can finish the login [4].
Option 3: let a credential service fill it
Steel's Credentials API, in beta, accepts a totpSecret with a stored credential and fills the TOTP code in Steel sessions [5].
Option 4: keep the seed in runnerID and fill the code over CDP
- ›1. Set up an authenticator on the agent's own seat, then save that seed once with save_authenticator, or in the owner console at https://api.runnerid.torchrunner.ai/console. It takes a base32 seed or an otpauth:// URI. The seed is encrypted and is not returned [8].
- ›2. When the agent reaches the code prompt, it calls fill_code with the site and the browser's CDP address. runnerID types the current code into the matching page. The code is not returned [8].
- ›3. The code is typed only into the host the seed was saved for (a leading www. is ignored) or a trusted subdomain, and the page URL is read again just before typing [8].
- ›If runnerID can reach the browser (a hosted browser or one on your own server): Agents that drive a browser runnerID can reach, such as a hosted browser (Browserbase, Steel) or one on your own server, get the strongest mode: runnerID types the password itself.
- ›If the browser is on your own laptop: When the browser runs on your own laptop, the helper uses its local route: the password passes through your own code once to be typed, and still never reaches the model.
A password or TOTP seed is encrypted with AES-256-GCM under a per-identity data key [8]. Tool results never include a password or seed. Only get_email_code and get_authenticator_code return a code, and each release is logged.
Hosted agents over MCP: get_authenticator_code
Hosted agents that connect over MCP get authenticator and emailed codes returned to them, and approvals and the log work the same. Typing a password into the page needs the runnerID helper next to the browser (Stagehand, Playwright or Browser Use), on a laptop or in a cloud container.
For those agents, get_authenticator_code returns the current six digit code for a site. The code lasts about 30 seconds, the release is logged, and the seed is never returned [8].
Connect over MCP at https://api.runnerid.torchrunner.ai/mcp with your API key as a Bearer token, for example: {"mcpServers": {"runnerid": {"type": "http", "url": "https://api.runnerid.torchrunner.ai/mcp", "headers": {"Authorization": "Bearer rid_YOUR_KEY"}}}} [8]. The guide at /guides/mcp-connector-claude-cursor covers Claude and Cursor.
MCP servers that return 2FA codes
- ›Authenticator App MCP: a local MCP server that gives an AI agent 2FA codes and passwords from the Authenticator App · 2FA desktop app. It needs an access token from the app [6].
- ›Bitwarden MCP server: Bitwarden's local MCP server for an AI assistant and a Bitwarden vault [7].
- ›runnerID by Torchrunner: get_authenticator_code returns the current code for a site from the seed runnerID stores, and fill_code types it without returning it.
Where the seed lives in each option
Entries for other tools come from their own pages. Not stated means the page did not say, as of October 24, 2026.
- ›Where the seed lives: Your code or its environment [1]
- ›Who makes and types the code: Your code
- ›Where the seed lives: sensitive_data in your script [2]
- ›Who makes and types the code: Browser Use, when the agent enters the bu_2fa_code placeholder [2]
- ›Where the seed lives: Your code [3]
- ›Who makes and types the code: Your Stagehand code [3]
- ›Where the seed lives: Steel's credential service [5]
- ›Who makes and types the code: Steel, in Steel sessions [5]
- ›Where the seed lives: The Authenticator App · 2FA desktop app [6]
- ›Who makes and types the code: Not stated
- ›Where the seed lives: runnerID, encrypted per identity
- ›Who makes and types the code: runnerID types it with fill_code, or returns only the code with get_authenticator_code
Questions
How does an AI agent get past an authenticator app code?
It generates the current six digit code from the TOTP seed and types it. The seed can sit in your code (otplib), in your framework (Browser Use bu_2fa_code), in a credential service (Steel), or in runnerID by Torchrunner, which types the code into the page with fill_code.
Where should a TOTP seed be stored for an agent?
Outside the prompt, and ideally outside the agent's own code. runnerID stores it encrypted with AES-256-GCM under a per-identity data key, and the seed is never returned.
Can a hosted agent get a 2FA code over MCP?
Yes. Hosted agents that connect over MCP get authenticator and emailed codes returned to them, and approvals and the log work the same. Typing a password into the page needs the runnerID helper next to the browser (Stagehand, Playwright or Browser Use), on a laptop or in a cloud container. The tool is get_authenticator_code, and each release is logged.
Does the agent ever see the seed?
Tool results never include a password or seed. Only get_email_code and get_authenticator_code return a code, and each release is logged.
What about codes sent by SMS?
A phone number for SMS codes is coming. Emailed codes work today: see the inbox guide at https://runnerid.torchrunner.ai/guides/ai-agent-inbox-verification-codes.
Sources, checked October 24, 2026
- ›1. otplib on GitHub: https://github.com/yeojz/otplib
- ›2. Browser Use, Authentication: https://docs.browser-use.com/open-source/customize/browser/authentication
- ›3. Browserbase, MFA handling template: https://www.browserbase.com/templates/mfa-handling
- ›4. Browserbase, Website authentication: https://docs.browserbase.com/platform/identity/authentication
- ›5. Steel, Credentials API: https://docs.steel.dev/overview/credentials-api/overview
- ›6. Authenticator App MCP on GitHub: https://github.com/firstorderai/authenticator_mcp
- ›7. Bitwarden, MCP server: https://bitwarden.com/blog/bitwarden-mcp-server
- ›8. runnerID API docs: https://api.runnerid.torchrunner.ai/llms.txt
otplib, Browser Use, Browserbase, Stagehand, Playwright, Steel, AgentMail and Authenticator App · 2FA belong to their owners. Bitwarden is a trademark of Bitwarden, Inc. Claude is a trademark of Anthropic. Cursor is a trademark of Anysphere. runnerID and Torchrunner are independent and are not affiliated with, endorsed by or sponsored by any of them.