# Using Vault

> If you already run HashiCorp Vault, keep tokens there and only references in your setup.

## When to use it

The default (a `secrets.json` encrypted with your passphrase) needs no server. If you already run Vault, keeping tokens in Vault KV v2 is better:

- Change a token in Vault and the next MCP server start uses it, without touching the repo or other machines.
- Access and audit go through your Vault policies.

## Set up

**AppRole** is the recommended login for both laptops and unattended machines. Give each machine its own role_id and secret_id; aisync logs in for a fresh token every time it uses Vault. A machine that was off for months still works, and a lost one is cut off by revoking its secret_id.

```sh
aisync vault login --addr https://vault.example.com --approle
```

Asks for the role_id and secret_id (or reads `AISYNC_VAULT_ROLE_ID`, `AISYNC_VAULT_SECRET_ID`), checks them and stores them in the keychain.

Storing a plain token also works:

```sh
aisync vault login --addr https://vault.example.com
```

Asks for a Vault token, checks it and stores it in the keychain. `VAULT_TOKEN` is used if set. The token needs read access to the paths you use, and write access if capture should move tokens there.

## Move tokens to Vault on capture

```sh
aisync capture default --vault claude/aisync
```

Tokens found in MCP servers go to `claude/aisync/<server>-<key>` (KV v2 mount `claude`) in the `value` field, and the setup keeps a reference:

```json
"SLACK_BOT_TOKEN": "{{vault:claude/aisync/slack-slack_bot_token#value}}"
```

You can write references by hand as `{{vault:<mount>/<path>#<field>}}`; the field defaults to `value`.

For an MCP server that talks to Vault itself (such as the Vault MCP server), `{{vault-token}}` passes the machine's current token, so no server token has to be stored anywhere:

```json
"args": ["run", "-i", "--rm", "-e", "VAULT_TOKEN={{vault-token}}", "hashicorp/vault-mcp-server"]
```

## On other machines

```sh
aisync vault login --addr https://vault.example.com
aisync pull default
```

A machine not logged in to Vault stops at pull and says what's missing. After the pull, aisync reads the value from Vault every time Claude Code starts the server.

## Verified behaviour

Checked against a real Vault (1.18):

- capture puts tokens in Vault and leaves only references in the repo
- another machine's pull is refused until it logs in to Vault
- after the pull, `aisync exec`, `aisync headers` and a real `claude mcp list` hand the Vault value to the servers
- changing only the value in Vault takes effect on the next server start, without a pull

## Any Vault works, within these limits

You choose the server with `--addr`, so a Vault you run yourself works. This version requires:

| Item | Supported |
|---|---|
| Secrets engine | KV v2 only. KV v1 mounts can't be read |
| Login | AppRole or a Vault token. No OIDC or userpass yet |
| Token expiry | Periodic and TTL tokens are renewed each time aisync uses them. A token with a max TTL still expires then; run `vault login` again |
| Certificates | Ones your system trusts. A self-signed CA can't be configured |
| Enterprise namespaces | Not supported |
| Servers | One Vault address per machine |

Scripts that call Vault themselves can take the same token with `VAULT_TOKEN=$(aisync vault token)`, so rotating it is one `aisync vault login`.

Give the token a policy that allows only the paths it needs. A root token in your setup opens all of Vault if that machine is compromised.
