1Password CLI¶
Access 1Password secrets from the command line with biometric authentication.
Overview¶
1Password CLI (op) provides:
- Secret access - Read passwords, API keys, credentials
- SSH agent - Use 1Password as SSH key storage
- Biometric unlock - Touch ID, Windows Hello
- Script integration - Inject secrets into scripts
- chezmoi integration - Templated dotfiles with secrets
Installation¶
macOS¶
Linux¶
# Debian/Ubuntu
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" | \
sudo tee /etc/apt/sources.list.d/1password.list
sudo apt update && sudo apt install 1password-cli
Verify¶
Initial Setup¶
Sign In¶
# Interactive signin
op signin
# With account shorthand
op signin my.1password.com
# First time setup
op account add --address my.1password.com --email you@example.com
Biometric Unlock (macOS)¶
- Open 1Password app
- Go to Settings > Developer
- Enable "Integrate with 1Password CLI"
- Enable "Touch ID for 1Password CLI"
Test biometric:
Session Management¶
# Get session token (without biometric)
eval $(op signin)
# Check current session
op account get
# Sign out
op signout
Reading Secrets¶
Secret Reference Format¶
Examples:
| Reference | Description |
|---|---|
op://Personal/GitHub/token | Token field from GitHub item |
op://Personal/GitHub/password | Password field |
op://Personal/GitHub/username | Username field |
op://Work/AWS/access_key_id | Custom field |
Read Command¶
# Read single secret
op read "op://Personal/GitHub/token"
# Read with vault specified
op read "op://Personal/GitHub/token"
# Output to variable
TOKEN=$(op read "op://Personal/GitHub/token")
Get Full Item¶
# JSON output
op item get "GitHub" --format json
# Specific field
op item get "GitHub" --fields password
# Multiple fields
op item get "GitHub" --fields username,password
List Items¶
# List all items
op item list
# List in vault
op item list --vault Personal
# List with tags
op item list --tags development
SSH Agent Integration¶
Enable SSH Agent¶
- Open 1Password app
- Go to Settings > Developer
- Enable "Use the SSH Agent"
Configure SSH¶
Add to ~/.ssh/config:
For Linux:
Add SSH Key to 1Password¶
- Open 1Password
- Create new item: SSH Key
- Either import existing key or generate new one
- The key appears in ssh-add -l
Verify SSH Agent¶
Per-Host Key Selection¶
In ~/.ssh/config:
Host github.com
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
IdentitiesOnly yes
Host work-server
IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
IdentitiesOnly yes
Environment Variable Injection¶
Using op run¶
Create .env.template:
DATABASE_URL=op://Development/Database/url
API_KEY=op://Development/API/key
SECRET_KEY=op://Development/App/secret
In Scripts¶
#!/bin/bash
# script.sh
export DATABASE_URL="$(op read 'op://Development/Database/url')"
export API_KEY="$(op read 'op://Development/API/key')"
python app.py
Docker Compose¶
Run with:
chezmoi Integration¶
Basic Template¶
In chezmoi template file (.tmpl):
# .gitconfig.tmpl
[user]
name = {{ .name }}
email = {{ .email }}
signingkey = {{ onepasswordRead "op://Personal/GPG/key_id" }}
[github]
token = {{ onepasswordRead "op://Personal/GitHub/token" }}
chezmoi Configuration¶
In ~/.config/chezmoi/chezmoi.toml:
Complex Templates¶
# .envrc.tmpl
export DATABASE_URL="{{ onepasswordRead "op://Development/Database/url" }}"
export AWS_ACCESS_KEY_ID="{{ onepasswordRead "op://Work/AWS/access_key_id" }}"
export AWS_SECRET_ACCESS_KEY="{{ onepasswordRead "op://Work/AWS/secret_access_key" }}"
Conditional Secrets¶
{{ if eq .chezmoi.hostname "work-laptop" -}}
export WORK_API_KEY="{{ onepasswordRead "op://Work/API/key" }}"
{{ end -}}
Script Integration¶
Bash Script Example¶
#!/bin/bash
# deploy.sh
set -e
# Get secrets
DB_PASSWORD=$(op read "op://Production/Database/password")
DEPLOY_TOKEN=$(op read "op://Production/Deploy/token")
# Use in deployment
curl -X POST \
-H "Authorization: Bearer $DEPLOY_TOKEN" \
-d "db_password=$DB_PASSWORD" \
https://api.example.com/deploy
Git Hooks¶
#!/bin/bash
# .git/hooks/pre-push
# Verify no secrets in code
if grep -r "$(op read 'op://Personal/GitHub/token')" .; then
echo "Error: Found secret in code!"
exit 1
fi
Cron Jobs¶
# Use with launchd or systemd for scheduled tasks
# Biometric won't work - use service account or session
# crontab
0 * * * * /path/to/script-with-op.sh
For unattended access, use service accounts.
direnv Integration¶
# .envrc
export DATABASE_URL="$(op read 'op://Development/Database/url')"
export API_KEY="$(op read 'op://Development/API/key')"
# Or with dotenv template
# .env.template
# DATABASE_URL=op://Development/Database/url
# API_KEY=op://Development/API/key
# .envrc
op run --env-file .env.template --no-masking -- direnv allow
Service Accounts¶
For CI/CD and automated systems without biometric:
Create Service Account¶
- Go to 1Password.com > Settings > Service Accounts
- Create new service account
- Grant vault access
- Save token securely
Use in CI/CD¶
# GitHub Actions
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
steps:
- name: Get secrets
run: |
DATABASE_URL=$(op read "op://Vault/Item/field")
Common Operations¶
Create Items¶
# Create login
op item create --category login \
--title "New Service" \
--vault Personal \
username=admin \
password=secretpassword
# Create with generated password
op item create --category login \
--title "New Service" \
--vault Personal \
--generate-password
Edit Items¶
# Edit field
op item edit "GitHub" password=newpassword
# Edit with vault
op item edit "GitHub" --vault Personal token=newtoken
Delete Items¶
# Delete item
op item delete "Old Service"
# Delete with confirmation skip
op item delete "Old Service" --force
Security Best Practices¶
- Use biometric - Enable Touch ID/Windows Hello
- Limit vault access - Only grant necessary vaults
- Audit access - Review 1Password audit logs
- Short sessions - Sign out when not needed
- Service accounts - Use for CI/CD, not personal tokens
Prevent Secrets in History¶
# Good - no secret in command
op read "op://Personal/GitHub/token" | pbcopy
# Bad - secret visible in history
curl -H "Authorization: $(op read 'op://...')" https://api.example.com
# Better
TOKEN=$(op read "op://Personal/API/token")
curl -H "Authorization: Bearer $TOKEN" https://api.example.com
unset TOKEN
Troubleshooting¶
Biometric Not Working¶
# Verify 1Password app settings
# Developer > Integrate with 1Password CLI
# Check agent is running
op signin --help # Should not ask for master password if biometric enabled
Session Expired¶
# Re-authenticate
eval $(op signin)
# Or with biometric
op read "op://Personal/Test/password" # Triggers biometric
SSH Agent Issues¶
# Verify socket exists
ls -la ~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock
# Test agent
SSH_AUTH_SOCK="$HOME/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" ssh-add -l
Item Not Found¶
# List items to find correct name
op item list --vault Personal
# Search for item
op item list | grep -i github
Reference¶
Useful Commands¶
| Command | Description |
|---|---|
op signin | Authenticate |
op signout | End session |
op account get | Current account info |
op vault list | List vaults |
op item list | List items |
op item get | Get item details |
op read | Read single field |
op run | Run with injected secrets |
Environment Variables¶
| Variable | Description |
|---|---|
OP_SERVICE_ACCOUNT_TOKEN | Service account auth |
OP_BIOMETRIC_UNLOCK_ENABLED | Biometric status |
OP_ACCOUNT | Default account |
See Also¶
- chezmoi - Dotfiles with secrets
- direnv - Environment management
- SSH Configuration - SSH setup
- Secrets Management - Secret storage overview