Repository navigation
Secrets and Logins
The login story is layered by who holds the secret: the human registers once, the keychain keeps it, the daemon injects it, the agent never sees it.
The simplest flow: a human logs in once in a visible window, the state is parked in the OS keychain, and every later run restores it.
curl -s -X POST http://127.0.0.1:8765/sessions/show -d '{"session":"setup"}' -H 'Content-Type: application/json'
# … human logs into the site …
navette state save devto --session setup
# forever after, any agent / any run:
curl -s -X POST http://127.0.0.1:8765/sessions/load -d '{"session":"work","store":"devto"}' -H 'Content-Type: application/json'The jar lives in the OS keychain; only metadata (name, origin, timestamp) ever leaves the daemon. macOS re-prompts on a new binary (ACL) — an implicit per-release consent.
The human saves a login once:
# navigate a session to the site's login page first — the credential binds to THAT exact origin
navette creds set mysite --session setup
# prompts for username + password on hidden stdinThen any agent fills the login form:
curl -s -X POST http://127.0.0.1:8765/login -d '{"site":"mysite","session":"work"}' -H 'Content-Type: application/json'Guarantees:
- The password is resolved inside the daemon and injected into the page. It never appears in the request, the response, or a log.
-
No read-back API at all —
GET /credslists sites, origins and usernames only. - The fill is refused on any other origin (403) — a hostile page or a prompt-injected agent can neither harvest the secret nor aim it at another site.
- The one honest limit: at fill time the password does reach the page — the same as human typing. The origin-binding is the defense.
2FA stays human by design:
curl -s -X POST http://127.0.0.1:8765/sessions/show -d '{"session":"work"}' -H 'Content-Type: application/json'
# the human does the 2FA / captcha / consent screen on the now-visible window
curl -s -X POST http://127.0.0.1:8765/sessions/hide -d '{"session":"work"}' -H 'Content-Type: application/json'Captcha policy — hard line: navette never solves a captcha and never helps bypass one. Not for legality-only reasons: automated captcha solving is fingerprint warfare you always lose, and it poisons the sessions you depend on. session_show is the designed answer.
WKWebView only runs a passkey ceremony when the app implements the WKUIDelegate panel runner — and navette does:
-
/healthreportsauth_ceremonyon builds with the plumbing. -
GET /sessionscarries a per-sessionauthstate while a sheet waits for the human. - The credential never crosses into the daemon: the gesture happens entirely inside Apple's system UI.
- The chain provably reaches Apple's
AuthenticationServicesAgent— verified in the unified log.
The honest limit (measured, logged): the system agent refuses to present the authorization sheet to builds without a real signing Team ID — Told not to present authorization sheet (ASC AuthorizationError 1 → ASAuthorization 1004). Ad-hoc and unsigned binaries (brew services included) get the ceremony cancelled before the sheet appears. A Developer ID–signed build is the unlock to retest — everything else is in place.
As a side effect of the same WKUIDelegate work, JS dialogs are now logged and auto-dismissed.
- See a password (there is no read-back route).
- Ask for a password in chat — automation flows route around credentials entirely (
/login, state jars,session_show). - Solve or bypass a captcha.
- Use a credential off its saved origin (daemon-side refusal).
See also Security for the enforcement table and CLI Reference for the creds/state subcommands.
slabbdev/navette · v1.9.0 · MIT — the browser for agents. One tiny Rust binary, the WebView your OS already ships.
navette — the browser for agents
- Home
- Use it
- Sessions, secrets, humans
- Ecosystem
- Evidence
- Project