Skip to main content

Bitwarden Secrets Manager

Pull API keys from Bitwarden Secrets Manager at process startup instead of storing them in plaintext inside ~/.tutou/.env. One bootstrap secret (a machine-account access token) replaces N per-provider keys, and rotating a credential becomes a single change in the Bitwarden web app.

How it works​

  1. You create a machine account in Bitwarden Secrets Manager, give it read access to a project, and generate an access token.
  2. Tutou stores that single token in ~/.tutou/.env as BWS_ACCESS_TOKEN.
  3. Every time tutou (or the gateway, or a cron job) starts, after ~/.tutou/.env has loaded, Tutou calls bws secret list <project_id> and sets the returned keys into os.environ.
  4. By default Tutou overrides values already in your environment, so Bitwarden is the source of truth — rotate a key once in the web app and every Tutou process picks it up on next start. Flip override_existing: false in config if you want .env to win instead.

Tutou honors a bws executable on PATH before checking PM selection. If neither exists, first use requests the pinned package from PM, subject to the lazy-install policy.

Why machine accounts (and why no 2FA prompt)​

Bitwarden Secrets Manager is designed for non-interactive workloads: machine accounts can't be 2FA-gated because there's no human in the loop. The access token is the credential. Anyone with it can read every secret the machine account has access to, so treat it like a high-value bearer token — store it in .env (not config.yaml), and revoke + regenerate from the Bitwarden web app if it ever leaks.

You set up the machine account in the web app, where your normal 2FA applies. After that the token is autonomous.

Setup​

1. Create a machine account and access token​

In the Bitwarden web app (or vault.bitwarden.eu for EU accounts):

  1. Switch to Secrets Manager from the product switcher.
  2. Create or pick a Project (e.g. "Tutou keys").
  3. Add your provider keys as secrets. The secret Name becomes the environment variable name — use OPENROUTER_API_KEY, ANTHROPIC_API_KEY, etc.
  4. Machine accounts → New machine account → My Tutou machine → Projects tab → grant Read access to your project.
  5. Access tokens tab → Create access token → Never expires (or pick a date) → copy the token (starts with 0.). Bitwarden cannot retrieve it again — keep the copy.

Secrets Manager is included on the Bitwarden free tier with limits; no paid plan needed to try this.

2. Run the wizard​

tutou secrets bitwarden setup

It will:

  1. If bws is absent, request its pinned package from PM.
  2. Prompt you for the access token (input is hidden). Stored in ~/.tutou/.env as BWS_ACCESS_TOKEN.
  3. Ask which Bitwarden region your machine account belongs to — US Cloud, EU Cloud, or self-hosted / custom URL. Stored in config.yaml as secrets.bitwarden.server_url and passed to bws as BWS_SERVER_URL.
  4. List the projects the machine account can see; pick one. Stored in config.yaml as secrets.bitwarden.project_id.
  5. Test-fetch the project's secrets and show you which env vars will resolve.
  6. Flip secrets.bitwarden.enabled: true.

Non-interactive setup is also supported via flags:

tutou secrets bitwarden setup \
--access-token "$BWS_ACCESS_TOKEN" \
--server-url https://vault.bitwarden.eu \
--project-id <project-uuid>

3. Confirm​

tutou secrets bitwarden status

From now on, every tutou invocation pulls fresh secrets at startup. You'll see a one-line summary in stderr the first time secrets are applied in a process.

CLI​

CommandWhat it does
tutou secrets bitwarden setupInteractive wizard (install binary, prompt for token, pick project, test fetch)
tutou secrets bitwarden statusShow config + binary version + token presence/validation
tutou secrets bitwarden tokenRotate the access token: validate the new token against Bitwarden, then store it in .env
tutou secrets bitwarden syncDry-run: pull secrets now and show what would be applied
tutou secrets bitwarden sync --applyPull and export into the current shell's environment
tutou secrets bitwarden installInstall or repair the PM-pinned bws binary. No Bitwarden authentication required.
tutou secrets bitwarden install --forceCheck and repair the managed copy. Valid entries can be reused without another download.
tutou secrets bitwarden disableFlip enabled: false; leaves token + project id in place

Rotating an expired or revoked token​

When the machine-account token expires, gets revoked, or the account is deleted, startup shows:

Bitwarden Secrets Manager: Bitwarden rejected the machine-account access token (BWS_ACCESS_TOKEN) — it was likely revoked, expired, or belongs to another region. (...)
Bitwarden Secrets Manager: → Run `tutou secrets bitwarden token` to paste a fresh access token ...

Fix it without re-running the whole wizard:

tutou secrets bitwarden token # masked prompt
tutou secrets bitwarden token --access-token 0.… # non-interactive

The command probes Bitwarden with the new token before writing anything — a rejected token leaves your current .env untouched. On success it stores the token, clears the fetch caches, and warns if the configured project is not visible to the new machine account.

Configuration​

Defaults in ~/.tutou/config.yaml:

secrets:
bitwarden:
enabled: false
access_token_env: BWS_ACCESS_TOKEN
project_id: ""
server_url: ""
cache_ttl_seconds: 300
encrypted_cache:
enabled: false
max_stale_seconds: 0
override_existing: true
auto_install: true
KeyDefaultWhat it does
enabledfalseMaster switch. When false, Bitwarden is never contacted.
access_token_envBWS_ACCESS_TOKENEnv var name that holds the bootstrap token. Change this if you already use BWS_ACCESS_TOKEN for something else.
project_id""UUID of the project to sync from.
server_url""Bitwarden region or self-hosted endpoint. Empty = bws default (US Cloud, https://vault.bitwarden.com). Set to https://vault.bitwarden.eu for EU Cloud, or your own URL for self-hosted. Plumbed into the bws subprocess as BWS_SERVER_URL.
cache_ttl_seconds300How long an in-process or disk fetch result is reused. Set to 0 to disable fresh-cache reuse.
encrypted_cache.enabledfalseStore the last successful fetch in an AES-GCM encrypted cache at ~/.tutou/cache/bws_cache.enc.json.
encrypted_cache.max_stale_seconds0When encrypted caching is enabled, allow that cache to be used only after network/timeout failures, up to this age. Authentication failures never use stale secrets. A successful encrypted write removes the legacy plaintext cache/bws_cache.json.
override_existingtrueWhen true, Bitwarden values overwrite anything already in env (so rotation in the web app actually takes effect). Flip to false if you want .env / shell exports to win locally.
auto_installtrueRequests the PM-pinned bws package when no binary exists. PM's lazy-install policy also applies.

Failure modes​

Bitwarden never blocks Tutou startup. If anything goes wrong, you'll see a one-line warning in stderr and Tutou continues with whatever credentials .env already had:

SymptomCauseFix
BWS_ACCESS_TOKEN is not setEnabled in config but token cleared from .envRe-run tutou secrets bitwarden setup
Bitwarden rejected the machine-account access token … invalid_clientToken revoked, expired, machine account deleted — or the token belongs to another region (e.g. EU token hitting the US identity endpoint)Run tutou secrets bitwarden token to paste a fresh token; for region mismatches re-run setup and pick EU/self-hosted (or set secrets.bitwarden.server_url)
bws exited 1: invalid access tokenToken revoked or wrongRun tutou secrets bitwarden token with a new token
bws timed outNetwork blocked or Bitwarden API slowCheck connectivity to api.bitwarden.com (or your server_url)
bws binary not availableNo PM selection or executable on PATH, and automatic installation is disabled or failedRun tutou secrets bitwarden install and read its diagnostic.
Checksum failureThe download does not match the PM lockStop and investigate the download source. Do not bypass the hash check.

Startup warnings now include a → remediation line telling you exactly which command fixes the failure.

Security notes​

  • The bootstrap token (BWS_ACCESS_TOKEN) is itself sensitive — anyone with it can read every secret the machine account has access to. Treat it the same as any other API key.
  • Tutou will refuse to let Bitwarden overwrite the bootstrap token itself, even with override_existing: true. If you store BWS_ACCESS_TOKEN as a secret inside the project, it's silently skipped during apply.
  • PM checks the managed archive against its SHA-256 hash in pm/lock.json. A mismatch aborts installation.
  • The same lock declares the version. First use does not resolve a "latest" release. External binaries remain outside these PM checks.

When NOT to use this​

  • Single-machine personal setups where ~/.tutou/.env is fine. You're trading one credential for another and adding a network dependency at startup.
  • Air-gapped environments that can't reach api.bitwarden.com.
  • CI/CD where the existing secrets-injection mechanism (GitHub Actions secrets, Vault, etc.) is already set up — pick one path, not two.

The good case for this is multi-machine fleets, shared dev boxes, gateway VPSes, or any setup where you want centralized rotation and revocation across multiple Tutou installations.