Sessions & Auth

Login & Credentials

Login is the step automation gets stuck on most often. This page lays out three reliable paths: drive the login form directly with snapshot → fill → click → wait, tuck accounts into the chrome-use auth credential vault for one-command replay, and handle Sign in with Google / OAuth plus Bitwarden passwords and passkeys. The goal is to have the agent complete login in a real browser without leaving passwords in your shell history.

The basic login flow

The most direct approach: open the login page, use snapshot -i to read the interactive elements in the form, pick out the @refs for the email, password, and submit button, fill them one by one, click, and finally use wait --url to confirm you've landed on the post-login page.

Form login
$ chrome-use open https://app.example.com/login
$ chrome-use snapshot -i

# Pick the @ref for the email / password / submit button out of the snapshot, then:
$ chrome-use fill @e3 "user@example.com"
$ chrome-use fill @e4 "hunter2"
$ chrome-use click @e5
$ chrome-use wait --url "**/dashboard"
$ chrome-use snapshot -i
ℹ️ Why snapshot first, every time
A @ref is a handle to an element in the current snapshot — it can go stale the moment the page changes. Get into the habit of running snapshot -i to grab the current refs before acting; it's far more stable than hardcoding selectors. The final snapshot -i is there to confirm login actually succeeded (and you didn't stall on a login page showing an error).
⚠️ Plaintext passwords leak
Writing a password straight into a command leaves it in your shell history, process list, and logs. Only do this for throwaway local debugging; any sensitive account should switch to the credential vault or Bitwarden below, so the password never touches the command line.

Credential vault (auth save / login)

For sites you log into over and over, store the credential in the local vault once and then replay it with a single command that auto-fills and submits. --password-stdin reads the password from standard input, keeping it out of shell history.

auth save + auth login
# Save a credential (password read from stdin — press Ctrl+D when done)
$ chrome-use auth save my-app --url https://app.example.com/login \
    --username user@example.com --password-stdin

# From then on, one command: open the login page, fill, click, wait for the form to finish
$ chrome-use auth login my-app
✅ How the vault and Bitwarden divide the work
auth save tucks credentials into chrome-use's local vault; the bwu below instead pulls them from Bitwarden. The two work together: keep the password in Bitwarden and fetch it just-in-time at login, so the credential never lands on the command line.

Sign in with Google / OAuth

Click the site's own Google login button, then snapshot -i: even when the GSI "Continue as <user>" button sits inside a cross-origin iframe, you'll still get a clickable @ref (Chrome 125+). If a account-picker popup opens instead, just switch to that popup and drive it — the relay follows the popup your click opened.

OAuth redirect flow
# Kick off the OAuth flow
$ chrome-use open https://app.example.com/auth/google

# Wait for the redirect to Google, then read a fresh snapshot
$ chrome-use wait --url "**/accounts.google.com**"
$ chrome-use snapshot -i

# Fill in the Google account, step by step
$ chrome-use fill @e1 "user@gmail.com"
$ chrome-use click @e2
$ chrome-use wait 2000
$ chrome-use snapshot -i
$ chrome-use fill @e3 "password"
$ chrome-use click @e4

# Wait for the redirect back to the app site
$ chrome-use wait --url "**/app.example.com**"
ℹ️ Reusing an already-logged-in browser is easiest
If your local Chrome is already signed into Google / the target site, rather than re-running the whole OAuth flow, just drive that real Chrome directly, or save its session state for reuse — see Sessions & persistence.

Pulling passwords and passkeys from Bitwarden

When you need a real username / password (or a passkey) rather than reusing a cookie, the sister tool bitwarden-use (bwu) can read them out of a Bitwarden / Vaultwarden vault, letting the agent log in with credentials instead of only going through OAuth. bwu get <item> returns the password (and a 2FA code), and bwu fido2 get extracts a passkey private key for sites that accept FIDO2 / WebAuthn passkeys.

bwu · pipe password / passkey into a field
# Install once
$ curl -fsSL https://raw.githubusercontent.com/leeguooooo/bitwarden-use/main/install.sh | sh

# Fetch an item's password (and 2FA), pipe it straight into the input
$ bwu get github.com | chrome-use fill '#password' --stdin

# When the site needs a FIDO2 / WebAuthn passkey, extract the passkey private key
$ bwu fido2 get
✅ Use --stdin to feed the password into a field
chrome-use fill '#password' --stdin reads the value to fill from standard input, so when you pipe it in from bwu, the password never appears in command-line arguments and never enters your history.

Handling two-factor authentication (2FA)

When you hit a second step that needs SMS / TOTP / a hardware key, the least painful approach is to let a human do that step while the script waits alongside for the redirect. On the default extension path driving your real Chrome, the window is already visible, so just do the second step yourself; hand control back formally with session handoff (see Sessions & Persistence) — after handoff the agent refuses driving commands on that session until you return it. --headed is only needed when you --launch a separate browser, paired with a longer --timeout to wait for the post-login URL.

2FA: human completes the second step
# Show the browser window, log in with credentials first
$ chrome-use open https://app.example.com/login --headed
$ chrome-use snapshot -i
$ chrome-use fill @e1 "user@example.com"
$ chrome-use fill @e2 "password123"
$ chrome-use click @e3

# Complete 2FA by hand in the window; the script waits for the redirect (up to 120s)
$ chrome-use wait --url "**/dashboard" --timeout 120000

HTTP Basic and cookie auth

Not every site uses a form. For HTTP Basic Auth, set the credentials before navigating; when you need to inject a session manually, you can set the cookie directly.

Basic Auth / cookie injection
# HTTP Basic: set username / password before navigating
$ chrome-use set credentials username password
$ chrome-use open https://protected.example.com/api

# Set an auth cookie manually
$ chrome-use cookies set session_token "abc123xyz"
$ chrome-use open https://app.example.com/dashboard

Log in once, skip it afterward

Login is expensive — don't redo it every time. After a successful login, save the cookies and localStorage to a state file, then load it later with --state to start up already "logged in." It's the most practical trick for skipping the whole OAuth / 2FA dance.

state save / --state reuse
# Log in once, save cookies + localStorage
$ chrome-use state save ./auth.json

# Later runs start up already logged in
$ chrome-use --state ./auth.json open https://app.example.com
ℹ️ Want automatic save / restore?
Use --session-name (or AGENT_BROWSER_SESSION_NAME) to automatically save and load a session by name, with no files to manage by hand. State files contain plaintext session tokens — the details on encryption, gitignore, and named sessions are all in Sessions & persistence.

Security notes

Login inevitably touches credentials and session tokens. A few baselines:

⚠️ A state file = a reusable key
A saved auth state is equivalent to a live login session — anyone who gets it can impersonate you. Treat it like a password: least privilege, encrypted, destroyed promptly. Don't use shared directories, and don't dump it into logs.