Multi-PIN
Owner-scoped PINs that give each team access to only their secrets.
Not everyone on the team needs access to every secret. vars lets you create owner PINs, which can only decrypt fields tagged with a specific owner.
How it works
Tag variables with owner metadata:
DB_PASSWORD : z.string() {
dev = "dev-db-pass"
prod = "prod-db-pass"
} (owner = "backend-team")
GA_TOKEN : z.string() {
dev = "ga-token-123"
} (owner = "frontend-team")Then create a PIN for that owner:
vars pin create backend-teamThe CLI:
- Derives a sub-key from the master key using HKDF
- Wraps that sub-key with the new owner PIN
- Re-encrypts all fields tagged
(owner = "backend-team")with the derived sub-key
The backend team's PIN cannot decrypt the frontend team's fields, or any unowned fields. This isn't access control enforced by the CLI; it's different keys.
Encrypted tokens show ownership
Owner-encrypted values include the owner in the prefix:
# Master-encrypted (no owner)
enc:v2:aes256gcm-det:<iv>:<ciphertext>:<tag>
# Owner-encrypted
enc:v2:aes256gcm-det:owner=backend-team:<iv>:<ciphertext>:<tag>The CLI uses this to skip fields it can't decrypt without trying.
Partial show/hide
When a backend team member runs vars show with their PIN, they get a partially decrypted file:
# Their fields — decrypted
DB_PASSWORD : z.string() {
dev = "dev-db-pass"
prod = "prod-db-pass"
} (owner = "backend-team")
# Other fields — still encrypted
GA_TOKEN : z.string() {
dev = enc:v2:aes256gcm-det:owner=frontend-team:...
} (owner = "frontend-team")
# Unowned fields — still encrypted
API_KEY = enc:v2:aes256gcm-det:...vars hide with an owner PIN only re-encrypts that owner's fields, leaving everything else untouched.
Sharing access
To give the backend team access, copy .varskey and delete the lines they shouldn't have:
pin:v1:aes256gcm:owner=backend-team:<salt>:<iv>:<ct>:<tag>Give them this key file and the PIN. No CLI command needed.
Unowned fields
Fields without (owner = "...") metadata are encrypted with the master key. Only the master PIN can decrypt them. Owner PINs skip them entirely.
Master PIN still decrypts everything
The master PIN holds the master key, which can derive any owner sub-key. It always has full access. Owner PINs can only decrypt their own fields.
Key rotation with owner PINs
vars rotate with owner PINs present will warn you that all owner PINs will be invalidated, then ask for confirmation. After rotation, re-run vars pin create for each owner to issue new PINs derived from the new master key.