I have an AI agent running 24/7 on a headless Mac Mini. It books tee times, posts to Instagram, reads my work email, tracks action items from meetings. To do any of that, it needs credentials. API keys, OAuth tokens, login passwords.
For a while, I was handling this the dumb way. Pasting keys into chat when the agent asked for them. Storing tokens in plaintext JSON files. At one point I had an Instagram session cookie sitting in a folder with default permissions.
If you're running an AI agent with any kind of real access, you need a better system. Heres what I landed on after trying a few approaches.
The problem with "just paste it"
When your agent says "I need the API key for X," the natural instinct is to just paste it into the chat. Quick, easy, done.
Except now that key is sitting in your conversation history. Which might get compacted, logged, or backed up somewhere you dont control. If you're chatting over WhatsApp or Telegram, that key is now on their servers too. And if your agent ever gets its context summarized, that key might end up in a summary file in plain text.
Even storing keys in environment variables or config files on disk isn't great if the permissions are wrong. I wrote about locking down file permissions in a previous post, but the real fix goes deeper than chmod.
Password managers aren't just for humans
The answer that actually works: use a password manager. Specifically, one with a CLI that your agent can call programmatically.
I use 1Password. Their CLI tool (op) lets you read secrets from vaults, inject them into commands, and run processes with credentials without ever writing them to disk. The agent never sees the raw password. It just says "give me the item called Morris Williams Golf Course from the Ace vault" and gets back exactly what it needs.
op item get "Morris Williams Golf Course" --vault Ace --fields username,password
No copy pasting. No plaintext files. No secrets in chat history. The password lives in 1Password and stays there.
The headless problem
This worked great until it didn't.
1Password's CLI normally authenticates through the desktop app. You unlock 1Password on your computer, and the CLI piggybacks on that session. Works fine if you're sitting at your laptop.
But my agent runs on a headless Mac Mini. No screen. No keyboard. No one sitting there to click "approve" when the CLI asks for biometric confirmation.
What happened in practice: the 1Password desktop app would lock after an idle timeout, and suddenly every op command failed with "account is not signed in." My booking sniper would miss a tee time because it couldn't pull credentials at 7 AM. My Instagram poster would fail because it couldn't read the session token.
I spent way too long trying to fix this by adjusting lock timeouts and security settings in the 1Password app. None of it stuck reliably on a headless machine.
Service accounts: the actual fix
The solution is 1Password service accounts. They're designed for exactly this. Non-interactive, headless, no desktop app required.
A service account gives you a token. You set that token as an environment variable (OP_SERVICE_ACCOUNT_TOKEN), and the CLI authenticates with it automatically. No biometric prompts. No idle timeouts. No "account is not signed in" at 3 AM.
Setting it up:
- Go to 1password.com, sign in
- Developer > Directory > Create a Service Account
- Name it something obvious ("AI Agent" or whatever)
- Give it read access to the vault where you keep your agent's credentials
- Save the token it generates (it only shows once)
- Set the token as an environment variable wherever your agent runs
In OpenClaw, I added it to the gateway config:
{
"env": {
"vars": {
"OP_SERVICE_ACCOUNT_TOKEN": "ops_your_token_here"
}
}
}
Thats it. The CLI just works now. Every time. At 3 AM on a headless machine with no one around.
What you can't do with service accounts
One limitation worth knowing: service accounts can't access your Personal or default Shared vault. You need a separate vault for your agent's stuff.
I created a vault called "Ace" (my agent's name) and put everything the agent needs in there. Golf booking credentials, Instagram tokens, OAuth secrets. The service account has read access to that vault and nothing else.
This is actually a feature, not a bug. The agent cant accidentally read my personal banking passwords or my Netflix login. It only sees what I explicitly put in its vault.
The rules I follow now
After going through this the hard way, heres my setup:
Never paste secrets into chat. Not over WhatsApp, not in the web UI, not anywhere. If my agent needs a credential, it pulls it from 1Password.
Never store secrets in plaintext files. No credentials.json with raw API keys. If something needs to be on disk (like an OAuth token), lock the permissions down to 600 and keep the directory at 700.
Use op run for one-off commands. Instead of exporting an API key and running a script, use op run which injects the secret as an environment variable only for that process. It never touches disk.
op run --env-file=.env.template -- python my_script.py
Use a dedicated vault. Don't give your agent access to your whole 1Password account. Make a vault just for it. Principle of least privilege isn't just corporate jargon, it's common sense when you have an AI with shell access.
Use service accounts for headless. If your agent runs without a screen, skip the desktop app integration entirely. Service accounts are built for this.
The bigger point
The temptation with AI agents is to move fast and figure out security later. I get it. Getting the agent to actually do useful stuff is the exciting part. But credentials are the one thing you really dont want to get wrong.
A leaked API key is annoying. A leaked OAuth token for your work email is a problem. An agent with shell access and credentials stored in the wrong place is how you end up explaining to IT why your Gmail got compromised by your own automation.
Take an hour. Set up a password manager with CLI access. Create a service account. Move your secrets out of chat and into a vault. Future you will appreciate it.