authstate
v0.2.1
Published
Log in once and maintain a shared Playwright storageState cookie jar for browser tools.
Downloads
181
Readme
authstate
authstate logs in to a web app once and keeps the browser session on disk as a Playwright storageState file, so other tools never handle passwords.
Each account gets its own file, called a jar. Tools that share an account share one login. Tools on different accounts never block each other.
Requirements
bunversion 1.2 or newer.- Google Chrome, or the Chromium that Playwright downloads.
Install
bun install
bun linkThere is no build step. The authstate command runs src/main.ts straight from source.
Configure
Copy the example file and fill in your own values.
cp .testing-credentials.example.yaml .testing-credentials.yamlThe file holds one entry per account.
app: example-app
default: basic-user
credentials:
basic-user:
purpose: basic plan account for smoke tests
email: [email protected]
password: replace-me
app_url: http://localhost:3000
signed_in_when:
url_matches: "http://localhost:3000/dashboard/**"appnames the jar. It falls back to the folder holding the file.defaultpicks the entry used when no--purposeis passed.purposeis free text.--purposematches an entry key or any part of it.email,passwordandapp_urlare required on every entry.signed_in_whenneedsurl_matches, orselector, or both. Without it a login refuses with exit code3.
The smallest useful command
authstate ensure --credentials .testing-credentials.yamlThat makes sure a valid jar exists and prints one JSON line on stdout.
Commands
ensurereuses a jar the expiry maths has not proven dead, else runs one headless login.loginalways opens a visible browser and writes the resulting jar. Use it when the account needs a code or a single sign on step.pathprints where the jar lives without touching the network.revokedeletes one account's jar and its lock.prunedeletes every dead jar in~/.authstate/.
authstate ensure --credentials .testing-credentials.yaml --purpose premium-user
authstate ensure --credentials .testing-credentials.yaml --force
authstate login --credentials .testing-credentials.yaml --headed
authstate path --credentials .testing-credentials.yaml
authstate revoke --credentials .testing-credentials.yaml --purpose premium-user
authstate prune --credentials .testing-credentials.yamlFeed the jar path into another tool. The path field of the JSON line carries it.
STATE=$(authstate path --credentials .testing-credentials.yaml | jq -r .path)
some-browser-tool --storage-state "$STATE"Flags
--credentials <path>the credentials file. Required.--purpose <name>which entry to use.--namespace <name>a second separate session on the same account.--forceskip the freshness check and log in now.--verifyopen a browser to confirm a jar the expiry maths already calls fresh.--headedaccepted only onauthstate login. That command opens a window anyway.--timeout <ms>per step timeout. Default20000.-h,--helpprint the help text and exit0.
--out was removed. It let a live credential land anywhere and broke the one-jar-per-account rule. Passing it now fails with exit code 2. Use --namespace instead.
Exit codes
| code | meaning | | ---- | ------- | | 0 | usable | | 1 | credentials rejected | | 2 | usage error | | 3 | credentials file invalid or assertion missing | | 4 | no entry matches / ambiguous | | 5 | lock timeout | | 6 | human step required | | 7 | tool could not run |
A browser that cannot start, or an app_url with nothing listening, is a browser-unavailable refusal. It still prints one JSON line and exits 7.
JSON output
ensure, login and path print one JSON line on stdout. Progress and errors go to stderr, so stdout stays clean.
{"tool":"authstate","version":"0.2.1","command":"path","ok":true,"status":"reused","reason":null,"app":"example-app","account":"basic-user","namespace":null,"path":"/Users/you/.authstate/example-app--basic-user.json","expires_at":null,"seconds_remaining":null,"expiry_source":"none","logged_in":null,"proof":null,"verified":false,"browser_launched":false,"exit_code":0}versiontracks theversionfield inpackage.json.statusis one ofreused,refreshed,logged-in,refused.expiry_sourceis one ofcookie,token,both,none.proofisassertion,not-proven-dead, ornull.reasonisnullwhen things went well, else a short reason code.
Design notes
- Jars live in
~/.authstate/, outside any repository. - A jar file is named
<app>--<account>.json, plus--<namespace>when set. - Parallel callers collapse into one login through a lock folder beside the jar.
- An entry with no password refuses instead of guessing, and points at
authstate login --headed. - Freshness comes from cookie and token expiry maths, so the common case opens no browser.
Security
- Your credentials file and your jars are local files. Never commit them.
- A jar holds live cookies and tokens. Treat it like a password.
- The bundled
.gitignorealready blocks credential and state files. - If a jar or a credentials file ever leaks, change the password and sign the account out everywhere.
Tests
bun testLicense
MIT. See LICENSE.
