.agents/skills/agent-testing/references/auth.md
Auth is the gate for all automated testing. Complete
Step 0.0 first so
SERVER_URL and ports are resolved, then verify auth before writing any test
step.
Initialize helpers first:
SCRIPT="./.agents/skills/agent-testing/scripts/setup-auth.sh"
TEST_ENV="./.agents/skills/agent-testing/scripts/test-env.sh"
eval "$($TEST_ENV --exports)"
Quick reference after initialization:
| Command | Purpose |
|---|---|
$SCRIPT status | Check all surfaces (server + CLI + web + Electron) |
$SCRIPT status --surface web | Check only the Web surface gate |
$SCRIPT cli-seed | Configure CLI API-key auth from the seeded key |
$SCRIPT cli | Interactive CLI device-code login (user must run) |
$SCRIPT open-chrome | Open Chrome at SERVER_URL with DevTools |
$SCRIPT web-seed | Sign in the seeded user and inject cookies |
pbpaste | $SCRIPT web | Inject a copied Cookie header into agent-browser |
$SCRIPT web-verify | Live-check agent-browser session auth |
Use localhost for Web auth; better-auth cookies are stored for localhost,
not 127.0.0.1.
| Surface | Mechanism | Persistence | Human interaction |
|---|---|---|---|
| CLI | Seeded API key or OIDC Device Code Flow | .records/env/agent-testing-cli.env + $HOME/.lobehub-dev | No for seed path; yes for device-code fallback |
| Web | Seeded better-auth login or cookie copy | ~/.lobehub-agent-testing/web-state.json + agent-browser session | No for seed path; copy cookie only as fallback |
| Electron | App's own login state | Electron user-data dir | Log in once manually in the app |
| Bot | Native apps (Discord/WeChat/…) logged in | Each app's own session | Once per app |
For the self-contained no-root-.env dev environment, seed the baseline user
and API key once:
./.agents/skills/agent-testing/scripts/init-dev-env.sh seed-user
source .records/env/agent-testing-cli.env
./.agents/skills/agent-testing/scripts/setup-auth.sh cli-seed
The seed step writes LOBE_API_KEY for humans and maps it to the CLI's current
auth variable, LOBEHUB_CLI_API_KEY. It also sets LOBEHUB_SERVER so CLI
commands hit the local server without needing a stored device-code token.
Use this for automated CLI verification:
cd apps/cli
source ../../.records/env/agent-testing-cli.env
bun src/index.ts <command>
Use device-code login only when testing against a non-seeded environment.
Credentials are isolated from the user's real CLI config via
LOBEHUB_CLI_HOME=.lobehub-dev, which the current CLI stores under
$HOME/.lobehub-dev.
cd apps/cli && LOBEHUB_CLI_HOME=.lobehub-dev bun src/index.ts login --server http://localhost:3010
--server flag is required — an env var does NOT work and login will hit
the wrong server without it.setup-auth.sh status (verifies
LOBEHUB_CLI_API_KEY when present, otherwise checks the stored server URL).UNAUTHORIZED on API calls means the token expired — re-run login.The Web test surface is agent-browser --session lobehub-dev. The user's
ordinary Chrome is only a cookie source; Chrome screenshots, Chrome Network
records, and Chrome logged-in state do not prove the agent-browser test session
is authenticated.
For the seeded local dev environment, use the automatic path:
./.agents/skills/agent-testing/scripts/init-dev-env.sh seed-user
./.agents/skills/agent-testing/scripts/setup-auth.sh web-seed
web-seed posts the seeded email/password to
/api/auth/sign-in/email, stores the returned cookie jar under
~/.lobehub-agent-testing/, converts it to Playwright storageState, loads it
into the agent-browser session, and verifies the session does not land on
/signin.
agent-browser --headed on macOS often creates the Chromium window off-screen —
the user can't see or interact with it, so manual login inside the agent-browser
session fails. Instead, copy the better-auth session cookie out of the
user's own logged-in Chrome and inject it as a Playwright-style state file.
Do not use this on production URLs — only local dev. Treat the cookie as a secret: don't paste it into shared logs, PRs, or commit it anywhere.
$SCRIPT status --surface web — green? Start testing. Do not ask for a Cookie header.$SCRIPT web-seed.$SCRIPT open-chrome opens Chrome at SERVER_URL with DevTools.Cookie: header from Network tab → any same-origin request → Request Headers → right-click Cookie: → Copy value. Must be from Network, NOT document.cookie (HttpOnly cookies are invisible to document.cookie).pbpaste | $SCRIPT web — filters to better-auth cookies (session_token, session_data, state), builds Playwright storageState, loads it into the agent-browser session (lobehub-dev), opens SERVER_URL, and asserts the URL is not /signin.agent-browser --session lobehub-dev open "$SERVER_URL/"
agent-browser --session lobehub-dev snapshot -i | head -20
storageState doesn't enforce the HttpOnly flag on load — the script stores
cookies with httpOnly: false, which is fine for local dev and sidesteps a
CDP-context quirk where HttpOnly cookies sometimes fail to attach.~/.lobehub-agent-testing/web-state.json so
setup-auth.sh status can report web-auth readiness across sessions.| Symptom | Cause | Fix |
|---|---|---|
Still redirects to /signin after injection | User pasted from document.cookie → missed HttpOnly session | Re-pull from Network request Headers, not console |
Script reports no better-auth cookies found | User pasted the wrong value, or the cookie parser regressed | Keep the raw Cookie: header as-is; run scripts/setup-auth.test.sh if the input looks valid |
| Login works briefly then expires | better-auth.session_token rotated (user logged out / signed in again) | Re-copy and re-inject |
| Domain mismatch | Cookie domain must be localhost literally, no leading dot for local dev | — |
The desktop app keeps its own persistent login state in its user-data
directory — log in once manually inside the app and it survives restarts of
electron-dev.sh. No injection needed. The standard check (do NOT hand-roll a
store eval) once Electron is up with CDP:
./.agents/skills/agent-testing/scripts/app-probe.sh auth
# → {"ok":true,"isSignedIn":true,"userId":"user_xxx"}
setup-auth.sh status runs this probe automatically when CDP 9222 is
reachable.
These recipes only cover local dev authentication. They do not:
Secure; HttpOnly; Domain=.lobehub.com
and must be delivered over HTTPS.--remote-debugging-port or a bot account.