AI agents / Sign in without the password

Let an AI agent sign in without seeing the password.

Give an agent a password and it ends up in its context: the chat, the logs, the tool output and the model provider’s servers. In Browz you store the sign-in once, and the agent asks Browz to use it: Browz types the password and the authenticator code into the page itself, only on the sites you allow, and the agent is told only that the field was filled. You decide exactly what each agent may do: its own key, its own profiles, only the sites you allow, sign-ins it can use on your computer but never read, and a person for the login.

In Browz 0.1.2 and later, on every plan. Free for 5 profiles. Paid plans from $4.99 a month, with a 14-day refund on your first payment.

Store it once; the agent never sees it# You, once, in a terminal (or Automate › Saved sign-ins in the app) browz credential add --label "Shop (Jane)" --username [email protected] \ --site shop.example.com --profile <profile id> --totp # Password: (hidden prompt) # TOTP seed (base32 or otpauth:// URI): (hidden prompt) # A key for this agent only. Stored sign-ins need browz:credentials:use, never in the default set. browz agent-token create --name "sign-in bot" --profiles <profile id> --sites shop.example.com \ --scopes browz:profiles:read,browz:browser,browz:credentials:use > ~/.browz-sign-in-bot.key chmod 600 ~/.browz-sign-in-bot.key

The problem

Where a password you give an agent ends up.

Most agents sign in the way a script does: someone hands them the password. From then on it is in places you do not control.

01

In the prompt or the chat

A password you paste becomes part of the conversation: kept in the chat history and its transcripts, and sent to the model provider with every turn that follows.

02

In an environment variable or a file

An agent that can run commands can print it, and anything it prints becomes tool output in its context, and from there in the same places as the chat.

03

In tool calls and logs

To type a password, an ordinary browser tool takes it as an argument, so it is written into MCP logs, traces, debugging output and whatever records the agent’s calls.

04

In front of a hostile page

A page that plants instructions can ask an agent to type the password somewhere else or repeat it. An agent that knows a password can be talked into using it.

How Browz does it

The agent points at the field. Browz types the value.

Six steps, the same for any agent on your computer or your own server.

  1. Store the sign-in once

    Run browz credential add with a label, the username, the sites it may be typed on and who may use it (one profile with --profile, a group with --group or every profile with --any), or use Automate › Saved sign-ins in the app. Browz asks for the password, and with --totp the authenticator seed, with a hidden prompt: secrets are never taken from the command line, where they would land in your shell history.

  2. Give the agent its own key

    Create a key with browz agent-token create, limited to that profile and that site, with the browz:credentials:use scope, which is never in a key’s default set. The key can use the sign-in; it can never add, change, remove or read one.

  3. The agent finds the sign-in

    On a sign-in page, browz_snapshot already names the stored sign-ins this agent may use there, by label and id. browz_credential_list gives each one’s label, a masked username such as j•••@example.com, its sites and whether it has a code. Never a password or seed.

  4. The agent asks Browz to fill a field

    It calls browz_credential_fill with the field’s ref from the snapshot and which value goes there. Browz checks the page’s address, the field and the limits, then types the value itself at the profile’s human pace, and the agent is told only that the field was filled.

  5. The page stays sealed until it changes

    While a filled secret is in the page, the agent cannot run script, take screenshots or wait for page text in that profile, and snapshots show the field as [value=<redacted>]. Submitting the form, which loads the next page, lifts it.

  6. Every fill is logged, never the value

    Each fill, refused ones included, is a row in your local action log and, for an agent key, in that key’s own log: the time, the profile, the page’s origin and path, the sign-in’s id, the field and the outcome.

What the agent calls, and all it gets backbrowz_credential_list {"id": "<profile id>"} → [{"id": "cred_3f…", "label": "Shop (Jane)", "usernameHint": "j•••@example.com", "sites": ["shop.example.com"], "hasTotp": true}] # never a secret browz_snapshot → the sign-in form, with refs: e14 email, e17 password browz_credential_fill {"id": "<profile id>", "credentialId": "cred_3f…", "ref": "e14", "field": "username"} browz_credential_fill {"id": "<profile id>", "credentialId": "cred_3f…", "ref": "e17", "field": "password", "submit": true} → {"filled": true, "credentialId": "cred_3f…", "field": "password", "submitted": true, "origin": "https://shop.example.com"} # all the agent gets back browz_credential_fill {"id": "<profile id>", "credentialId": "cred_3f…", "ref": "e9", "field": "totp", "submit": true} # Browz works the code out at that moment
What your log recordsbrowz agent-token log --agent <key id> # one row per call, refused ones included, kept 90 days: # time · tool browz_credential_fill · profile · page https://shop.example.com/login # credential cred_3f… · field password · outcome ok · reason filled (never the value)

Examples

Working in minutes.

The same sign-in and key, used from Claude Code over MCP and from any language over the Local API on 127.0.0.1. Replace <profile id> with a profile from browz list.

Claude Code, over MCP# 1. Store the sign-in and make Claude Code its own key (the two commands above), then: claude mcp add browz -e BROWZ_LOCAL_AGENT_TOKEN_FILE=$HOME/.browz-sign-in-bot.key -- npx -y @browz/mcp # 2. Ask Claude Code: # Start the Browz profile <profile id>, open https://shop.example.com/login and sign in # with the saved sign-in "Shop (Jane)". Never ask me for the password. # # It calls browz_profile_start, browz_navigate, browz_snapshot, browz_credential_list, # browz_credential_fill for each field, then browz_snapshot to check it is signed in.
Local API, with curlKEY=$(cat ~/.browz-sign-in-bot.key) # the agent's key, not your Local API token API=http://127.0.0.1:50333 curl -s -X POST $API/api/v1/browser/start -H "Authorization: Bearer $KEY" -d '{"id":"<profile id>"}' curl -s -X POST $API/api/v1/browser/navigate -H "Authorization: Bearer $KEY" \ -d '{"id":"<profile id>","url":"https://shop.example.com/login"}' curl -s "$API/api/v1/credential/list?profileId=<profile id>" -H "Authorization: Bearer $KEY" curl -s -X POST $API/api/v1/browser/snapshot -H "Authorization: Bearer $KEY" -d '{"id":"<profile id>"}' curl -s -X POST $API/api/v1/credential/fill -H "Authorization: Bearer $KEY" \ -d '{"id":"<profile id>","credentialId":"cred_3f…","ref":"e14","field":"username"}' curl -s -X POST $API/api/v1/credential/fill -H "Authorization: Bearer $KEY" \ -d '{"id":"<profile id>","credentialId":"cred_3f…","ref":"e17","field":"password","submit":true}' # {"code":0,"data":{"filled":true,"credentialId":"cred_3f…","field":"password","submitted":true,"origin":"https://shop.example.com"}}

Claude Desktop, Cursor and every other MCP client take the key the same way, as BROWZ_LOCAL_AGENT_TOKEN_FILE in the server’s environment: see the setup docs. Never put the key on a command line, and never give an agent your Local API token.

To see it end to end, run the stored sign-in recipe: a demo site on your computer, a stored password and authenticator code, and an agent (a script or Claude Code) that signs in without seeing either.

By design

What it does, and what it leaves to you.

Browz signs an agent in only where you said it may, and hands everything else to a person.

  • It leaves CAPTCHAs, passkeys and other prompts to a person. CAPTCHAs, passkeys, security keys, push approvals and codes sent by text or email always go to a person: Browz never solves or bypasses them. For those the agent calls browz_request_human: automation pauses on that profile, its window comes to the front with a notification, you finish the step, and the agent carries on in the same signed-in session. On a profile running headless, the agent stops and tells you.
  • It types only on the sites you allowed. A sign-in is filled only where its own sites and, for a key, the key’s allowed sites both match the page, over https. Anywhere else the fill is refused and logged.
  • It types only into real sign-in fields. A password goes only into a password field, and a code into a password field or one marked for one-time codes. A sign-in page whose code box is a plain text field is refused, and the agent hands that step to you.
  • It runs on your computer, not through our server. Stored sign-ins work with the MCP server and the Local API on your computer or your own server. With the hosted MCP server at mcp.gobrowz.com, in free public beta, they stay local on purpose: agents in the cloud hand sign-ins to you instead.
  • It hides the password and the code, not the username. The list masks the username, so it is not sent to the AI just to choose between accounts. Once typed into the page, the username shows in snapshots like any other text.
  • It paces itself. Each sign-in can be filled 12 times in any 10 minutes, and every fill also counts against the key’s own limits per minute and per day.

Security model

Who can see a stored sign-in.

In plain words, from the code that stores and types it.

Where it is kept

In the Browz agent’s own database on your computer, not on our servers and not in sync. The secret part is sealed twice: under your operating system’s keystore (the macOS Keychain or Windows DPAPI), then with this installation’s own key (AES-256-GCM), so a copy of the data folder alone opens nothing. On Linux, or where no keystore can be used, the installation’s key protects it alone, and the list says so.

Who can read it back

Nobody, through Browz. No MCP tool, Local API route or screen returns a stored password, seed or secret field: you can replace one, not display it, and diagnostics bundles scrub them. A key that may use stored sign-ins never receives the browser’s debugging endpoint, which could read a typed value out of the page.

What the AI and its provider see

The label, a masked username, the sign-in’s id and “filled”. The password and the code never enter the agent’s context, so they are never part of its prompt, its transcript or its tool results, and a verbatim copy of a filled value in a page result is scrubbed.

What stays in your hands

Browz governs what an agent does through Browz. A page you allowed can still leak a value it was given, by copying it in a changed form or sending it to its own server, so store sign-ins only for sites you trust with them. A program that runs as the same computer user as Browz can read its data folder, so run an agent you do not trust under another user or in a container. If the Browz agent restarts, it closes the profile’s browser before it answers any request, so a filled page is never open to an agent without this protection.

Turning it off

Revokebrowz agent-token revoke <key id> --stop-browsers # this agent, for good browz agent-token stop-all # every agent at once browz credential remove <credential id> # the sign-in itself

In the app, Automate › Agent keys has the same revoke, resume and Stop all agents buttons, and the key’s activity log.

And the browser itself

The same browser your other agents get.

The profile the agent signs in to is an ordinary Browz profile: its own cookies, storage and proxy, kept signed in for the next run. Underneath, every profile’s fingerprint is set in the browser engine itself, not by a script on top, and you can test it yourself (engine-level vs injected scripts).

Stored sign-ins are for accounts you are entitled to use. Use agents only where each site’s terms allow it: our acceptable use policy applies to agents the same as to people.

FAQ

About signing an agent in.

Can the agent read the password?

No. It never receives it: Browz types the value into the page itself and answers only that the field was filled. While the value is in the page, script, screenshots and text waits are refused in that profile and snapshots show the field as redacted. One part stays with you: a page you allowed can still leak a value it was given, so store sign-ins only for sites you trust.

Can the model provider see it?

The password and the code never enter the agent’s context, so they are not in anything the agent sends to its model. What the model sees is the sign-in’s label, a masked username and the word “filled”. The username itself shows in the page once it is typed.

What if the page is a phishing copy?

Then nothing is typed. Browz reads the tab’s address from the browser at the moment of the fill and compares whole host names in their ASCII form, so example.com never matches badexample.com, example.com.evil.net or a look-alike with a Cyrillic letter. The page must be https, every frame around the field must match too, and fields in frames from other sites cannot be reached. A key with allowed sites adds a second check of its own.

Does it work with two-factor codes?

Yes, with authenticator (TOTP) codes: store the seed with --totp, and Browz works out the code at the moment of the fill (SHA1, SHA256 or SHA512, 6 to 8 digits). Codes sent by text or email, passkeys, security keys and push approvals go to a person through browz_request_human.

How do I revoke it?

Run browz agent-token revoke with the key’s id to end that agent for good, or browz agent-token stop-all (Stop all agents, in the app) to stop every agent at once. A fill under way is checked again before the value is taken from the store and before the form is submitted. browz credential remove deletes the sign-in itself.

Does it work with Claude.ai or other hosted agents?

A hosted agent hands the sign-in to you with browz_request_human: stored sign-ins stay with agents on your computer, on purpose. Claude Code, Claude Desktop, Cursor and every agent that runs the local MCP server or calls the Local API can use them.

What does it cost?

Agent keys and stored sign-ins are part of Browz on every plan, Free included, and run on your computer without our server. Free for 5 profiles. Paid plans from $4.99 a month, with a 14-day refund on your first payment.

Get started

Your agent signs in. The password stays yours.

For Mac, Windows and Linux. Free for 5 profiles.