Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/onepassword

Resolve 1Password Connect item fields for secret-aware fetch with website host allowlisting.

README.md

98 lines · 5.2 KB · Markdown

@kentcdodds/onepassword

Intent

Bind 1Password Connect as a Kody custom secret provider so agents can use {{secret/1password:…}} placeholders in secret-aware fetch without ever seeing vault values. Resolve item fields over Connect, allowlist hosts from the item's websites or URL fields, and keep grants on item-id refs (UUID or 26-char Connect ids).

Optionally deploy the official Connect Server (connect-api + connect-sync) to Fly.io via ./connect/deploy-fly.

Setup

  1. Run a 1Password Connect Server (or deploy with this package — see Connect on Fly below) and mint a Connect token with read access to the vaults you need.
  2. Save the Connect token as the user-scoped secret ONEPASSWORD_CONNECT_TOKEN (never paste the token into chat): configure ONEPASSWORD_CONNECT_TOKEN. After you know your Connect hostname, edit the secret and add that host to allowedHosts if needed.
  3. Turn on Custom secret providers for your account (feature flag) from Custom secret providers.
  4. Bind this package on Secret providers (or secretProviderBind) with:
    • provider: 1password
    • door secret: ONEPASSWORD_CONNECT_TOKEN
    • config: {"connectHost":"https://kody-onepassword-connect.fly.dev"} (or your Connect host)
  5. Prefer item-id refs so grants work without a vault round-trip: {{secret/1password:i/<item-id>/password}} — Connect item ids are usually 26-char lowercase alphanumeric (not UUIDs); UUIDs are still accepted.

Connect on Fly

Default app: kody-onepassword-connecthttps://kody-onepassword-connect.fly.dev

  1. From 1Password Developer → Connect servers, download 1password-credentials.json, Base64-encode it, and save as ONEPASSWORD_CONNECT_OP_SESSION (Base64 of the file — not raw JSON). Approve hosts api.machines.dev and api.fly.io on that secret.
  2. Ensure flyApiToken exists with the same Fly API hosts approved (update hosts if needed).
  3. Deploy:
import deploy from 'kody:@kentcdodds/onepassword/connect/deploy-fly'
const result = await deploy()
// => { ok: true, appName, url, region, bind, ... }  // no secret values
  1. Smoke GET /heartbeat, then GET /v1/vaults with the Connect Bearer token.
  2. Bind with config: { connectHost: 'https://kody-onepassword-connect.fly.dev' }.

Why Base64 in the secret? Fly Machines config.files.raw_value expects Base64 file bytes. deploy-fly expands {{secret:ONEPASSWORD_CONNECT_OP_SESSION}} into that field, writes /home/opuser/.op/1password-credentials.json, and sets container env OP_SESSION to that path (official Connect semantics). Kody only expands placeholders inside secret-aware fetch, so the secret must already be Base64. Do not set a Fly app secret named OP_SESSION to Base64 — that overrides the path. Do not use raw ONEPASSWORD_CONNECT_CREDENTIALS_JSON as the file bytes secret.

Exports: ./connect, ./connect/source, ./connect/deployment-guide, ./connect/deploy-fly.

Placeholder grammar

FormNotes
{{secret/1password:i/<item-id>/<field>}}Preferred. Canonical grant key. Item id: UUID or 26-char Connect id (^[\da-z]{26}$).
{{secret/1password:op://Vault/<item-id>/<field>}}Synonym when the item segment is already an id.
Name-based op://Vault/Item/passwordNot locked/granted until you switch to an item-id segment.

Field matching (in order): field id, field label (case-insensitive), then purpose shortcuts passwordPASSWORD, usernameUSERNAME, notesNOTES.

Host allowlist (fail closed if empty): hostnames from item.urls[].href websites, plus fields typed/labeled as URL (Secure Notes often have an empty websites list but a URL field — point that field at the fetch host, e.g. https://discord.com).

Done when

  • Connect is reachable at your connectHost (Fly deploy optional).
  • secretProviderBind succeeds with this package and your Connect host config.
  • An ad hoc secret-aware fetch to an allowlisted host resolves {{secret/1password:i/<item-id>/password}}.
  • Saved packages that need the ref have an Allow grant from secretProviderLock.

See AGENTS.md for agent notes.