Skip to content

Login with 1Password: connect a vault, agents fetch items when needed - #708

Open
time-attack wants to merge 2 commits into
yc-software:mainfrom
time-attack:keychain-1password-login
Open

Login with 1Password: connect a vault, agents fetch items when needed#708
time-attack wants to merge 2 commits into
yc-software:mainfrom
time-attack:keychain-1password-login

Conversation

@time-attack

@time-attack time-attack commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Login with 1Password

Users can now connect their 1Password from the keychain page, and agents fetch credentials out of the shared vault at the moment a task needs them — vault contents are never copied into qm's store.

1Password has no consumer OAuth for third-party sign-in; its sanctioned path for agent access is a service account scoped to a vault (their agentic-AI guidance). This PR rides that path with the machinery the keychain already has:

  • Connect — a 1Password card under Linked accounts mints the existing one-time secret-drop page, prefilled as service: 1password, envKey: OP_SERVICE_ACCOUNT_TOKEN, with a link to 1Password's service-account setup. The token lands encrypted as a normal keychain credential; Disconnect deletes it (revoking its grants, via the existing confirm flow).
  • Use when needed — the token is a normal env credential, so every existing consent gate applies unchanged: implied in the owner's own DM, grant/ask + audit everywhere else, standing vs once, revocation. Once OP_SERVICE_ACCOUNT_TOKEN is in the agent's shell, the agent reads exactly one field at the moment of use (op read "op://vault/item/field").
  • Teach the agent — the keychain manifest gains a short block (only when a 1password credential is visible) explaining the token is vault-scoped and how to read single fields; a seeded 1password skill carries the full guidance (install op into $HOME, find the item, read one field, hygiene).
  • Bug fix en routedefaultEnvKey("1password") produced 1PASSWORD_TOKEN, an invalid env-var name that made saving any digit-leading service without an explicit envKey fail; it now prefixes an underscore.

No new dependency, route, or storage. The vault key never enters qm's database beyond the encrypted service-account token itself, and per-item values exist only in the using shell.

Deliberately not built (upgrade path if token-level granularity proves too coarse): per-item reference credentials resolved core-side via @1password/sdk, so the manifest could list individual vault items and the token would never reach a sandbox.

Demo

Connect (drop page is the existing secret-drop form, prefilled):

disconnected
drop page

Connected:

connected

QA

  • test/keychain.test.ts (44 pass — manifest hint presence/absence, digit-leading envKey), plugins/web-ui/test/keychain-flow.test.ts (11 pass), root typecheck + lint, web-ui typecheck.
  • Live dev-instance (--no-slack): drove the full flow in a browser — card → Connect → one-time page → submit token → connected card + stored 1password credential with OP_SERVICE_ACCOUNT_TOKEN; no console errors. (Local note: my dev instance had a stale ngrok PUBLIC_WEB_URL, so the drop link's host was rewritten to the local portal for QA; the path+token are host-independent.)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

… needed

A 1Password card on the keychain page mints the existing one-time secret-drop
page for a vault-scoped service-account token (1Password's sanctioned path for
agent access; no consumer OAuth exists). The token lands as a normal keychain
credential, so every existing consent surface — grants, asks, standing vs once,
audit, revocation — gates it unchanged. Once it is in the agent's shell, the
agent fetches exactly the item a task needs at the moment of use with the op
CLI; vault contents are never copied into the platform's store.

The keychain manifest teaches the op-read flow whenever a 1password credential
is visible, and a seeded skill carries the full guidance (install, find, read
one field, hygiene). defaultEnvKey now prefixes an underscore for services
whose name starts with a digit, which previously produced an invalid env-var
name and made saving such a credential without an explicit envKey fail.
… is optional

The one-time drop page set autocomplete=off on every field, which told the
user's password manager to stand down at exactly the moment they are asked to
produce a secret. Secret fields now advertise current-password and carry a
field name, so a manager (1Password, browser built-ins) offers to fill.

The 1Password card's copy now leads with the fact that connecting a vault is
optional — the agent already asks for a credential just in time and the user
pastes it once — so the card reads as the stop-asking-me upgrade, not a setup
requirement.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant