Updated: using 1Password and direnv to store developer secrets

I previously wrote about how i’d implemented a combination of 1Password’s CLI and direnv to avoid storing passwords on disk. This works great, most of the time. The problem comes when i want to add a secret and i’m in the middle of a complex multi-agent task – because the environment is loaded once before Claude or Codex or whatever starts, adding or rotating credentials during a build (e.g. if the agent needs an API key to a new service, or accidentally exposes a secret to its context) is tricky. So i’ve evolved the system slightly.

What’s changed

The main difference is that i now create a 1PW Service Account per project. This service account has read only access to the vault for a single project, and is loaded by direnv in to OP_SERVICE_ACCOUNT_TOKEN. All other secrets are injected at runtime using op run.

Initial setup – follow most setup steps from the original post

Initial setup remains the same – install 1PW, create a vault per project, add secrets to the vault.

Create a Service Account

This is the bit i found trickiest – mainly because it’s so hard to figure out where you need to create the actual account! You can’t do it in the desktop app, you need to go to the website. Once you log in, click Developer on the left. Create a new service account for the project.

  • You cannot change the grants assigned to a Service Account after creating it – but that’s ok, you can just create a new one.
  • give it read only access to the vault for the project, no other resources.
  • Store the key in 1Password – i store it in the vault of the project itself. There’s zero additional security implications of having the key there. It needs to live in the environment anyway! Let’s assume you save it in op://project/1pw/service_account_key

Create .envrc to load the Service Account

very simple. This loads the service account token from the vault. This will require biometrics – but after this, all op calls will use this token, so no longer require biometrics.

export OP_SERVICE_ACCOUNT_TOKEN="$(op read 'op://project/1pw/service_account_key')"

Run direnv allow

This authorizes

Create .env.tpl in the project folder

All our secrets are listed here. They’re only evaluated when we need them.

export MY_SECRET="op://project/service/secret"
export OTHER_SECRET="op://project/other_service/secret"

Run your app using op run

You (or your agent) can now use 1PW any time to inject the environment e.g.

exec op run --env-file ".env.tpl" -- <your command>

I might run Fastlane…

exec op run --env-file ".env.tpl" -- bundle exec fastlane beta

You could even have different template files for different parts of the app (e.g. in a monorepo), as long as the secrets are all in the same 1PW vault.

Overall this has simplified things for me significantly – I can add new credentials, or rotate existing ones, without needing to teardown my multiagent session.


Leave a Reply

Your email address will not be published. Required fields are marked *