Support 1Password op:// secret references in settings.json env section
Status Open
Maintainer reply None cached
Workaround ✓ Mentioned in thread ↓
Activity 12 comments · opened Feb 6, 2026
Feature Request
Support op:// secret references in the env section of settings.json (and .claude/settings.json), so that API keys and other secrets can be resolved from 1Password at startup without wrapper scripts.
Desired behavior
{
"env": {
"ANTHROPIC_API_KEY": "op://Private/Claude API Key/credential"
}
}
Claude Code would detect op:// prefixed values and resolve them via op read (1Password CLI) before use.
Current workarounds
apiKeyHelperscript that callsop read— works forANTHROPIC_API_KEYonly, not for arbitrary env vars (e.g., MCP server tokens).op run -- claudewrapper — works but requires a separate.envfile and remembering to always launch Claude Code through the wrapper.
Why this would be useful
- 1Password CLI (
op) is widely adopted for secret management in developer workflows - Many tools already support
op://references natively (e.g., Docker, various CI systems) - It would allow secure, declarative secret injection for both API keys and MCP server environment variables without wrapper scripts
- The
envsection in settings.json is the natural place to configure this
Implementation notes
- Only resolve
op://references ifopCLI is available in$PATH - Could generalize to a pluggable secret resolution mechanism (e.g.,
aws-secretsmanager://,vault://) in the future - Should fail with a clear error message if
opis not installed or not authenticated
---
This issue was generated with Claude Code
12 Comments
Opus 4.6 initially hallucinated this feature, so I asked it to file a feature request :-). Though, ambiguity for url handling there could cause a problematic behavior.
Good point about the ambiguity. Instead of overloading
envvalues with URL-scheme detection, a dedicatedsecretssection would be cleaner:This way:
envstays plain — values are used as-is, no surprise resolutionsecretsexplicitly signals that values are URI references to be resolved at startupop://,aws-sm://,cmd://, etc.) determines the resolver — extensible without ambiguitycmd://scheme could cover any secret manager via shell command, similar to howapiKeyHelperworks but for arbitrary env varsThis avoids the footgun where someone has a legitimate env value starting with
op://and gets unexpected behavior.---
This comment was generated with Claude Code
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
There is ambituity and potential security issue - should this secrets be available only in settings.json context, or like env - passed to environment of everything under claude.
Running into this with a custom Swift MCP server that needs an API token from 1Password. My current workaround in
.mcp.jsonshells out toop read:This works only if
ophas an active biometric session before Claude Code starts. If the session expires or wasn't established, the MCP server silently fails to connect. The/mcpreconnect command also fails because it spawns the subprocess non-interactively, soopcan't prompt for biometric auth. The only fix is toop readmanually in a terminal, then restart Claude Code.Security note: Native support would improve the security posture over current workarounds. To make this reliable today, you end up either pre-exporting the token as an environment variable (visible via
ps aux) or maintaining a long-livedopsession. Nativeop://resolution at startup with a biometric prompt would be both more secure and more reliable.Worth noting that
op://is a well-established URI scheme already supported by Docker, GitHub Actions, and various CI systems. It's not a novel pattern.On the auto-detected duplicates:
keychain://,credential://,pass://), which is a different approach fromop://resolution. Related but distinct feature.$VARexpansion insettings.jsonfor hooks and general config portability, not about resolving secrets from external credential managers.Worth noting that mentioned workaround doesn't help for http MCP servers.
I would also like to express interest in this feature. In addition, based on @ei-grad question, I would like to request those values actually being added to the environment.
Here is an example of how that can be useful:
When interacting with
gh, I actually useop plugin run -- gh, which reads my token from 1password and setsGITHUB_TOKENfor the execution ofgh. However, because claude code executes each command in a separate bash instance, that causes 1password to request my password for every singleghexecution.Being able to set
GITHUB_TOKENfor claude, as part of settings.json, so that it has it readily available for that session, would be great.Research: Why
opfails inside Claude Code's sandboxSpent some time debugging this. Sharing findings for anyone hitting the same wall.
Root cause
The
opbinary is setgid (-rwxr-sr-x, grouponepassword-cli). The 1Password desktop app validates that connecting processes belong to this group before accepting socket connections.Claude Code's sandbox uses bubblewrap (
bwrap), which creates a new user namespace. Inside user namespaces:nobodySo
opconnects to the 1Password daemon socket without theonepassword-cligroup credential, and the daemon rejects it with "connection reset".What doesn't help
additionalDirectorieswith socket paths (~/.1password,/run/user/1000) — the sockets are reachable (verified with raw Python socket connect), butopfails at the group credential check, not at socket accessHTTP_PROXY,ALL_PROXYetc. that the sandbox injects) — no effectOP_CONNECT_HOSTor otheropenv vars — same failureWhat works today
op run --env-file .env.op -- claudewrapper (one unlock, all secrets as env vars)OP_SERVICE_ACCOUNT_TOKEN(bypasses desktop app entirely, no setgid needed)Suggestion for Claude Code
Native
op://resolution (as proposed in this issue) would be the clean fix, since Claude Code itself runs outside the sandbox and could resolve secrets before passing them to sandboxed subprocesses. Thesecretssection idea from @ei-grad's comment would work well for this.Alternatively, if the sandbox could be made to preserve the calling process's supplementary groups (or at least allow setgid binaries),
opwould work natively. But that's probably a harder change given bwrap's security model.For anyone using @baelter's "pre-resolving specific tokens in a shell alias" approach -- I wrote up a detailed version of this with fish and bash examples using KeePassXC (via
keepassxc-proxy-getpw): https://mareksuppa.com/til/keepassxc-claude-code-api-keys/The gist is a shell function that fetches the key at invocation time and passes it as an inline env var prefix to
claude, so it's scoped to that process only. The same pattern works withop read,bw get password,pass show, etc.This covers the
ANTHROPIC_AUTH_TOKEN/ANTHROPIC_BASE_URLcase for third-party providers, and also works for MCP server secrets since MCP server processes inheritclaude's environment -- just add more secrets to the wrapper. That said, it gets unwieldy with many servers, which is another argument for the nativesecretssection @ei-grad proposed./tmp/issue-23642-comment.md
I am using @baelter's "pre-resolving specific tokens in a shell alias" approach as a workaround, but I am still seeking for a more secure solution. This approach exposes secretes to all skill scripts, MCPs (if not mannually configured), and other tools executed by Bash(). Any malicious code can easily get these secretes.
Quick update: I've moved on to hooks loading credentials from a vault during skill execution, so secrets aren't sitting in the env the whole session.