Scoping the API key you hand an AI agent, on purpose
The MCP credential you hand an agent is the whole permission boundary. Practical key hygiene: dedicated keys, rotation, revocation, and OAuth vs. API keys.
By Gabriel Lara, Developer Relations, Norbelys
Founder-reviewed ·How we research and correct articles
Every MCP call Norbelys receives is authenticated by the credential riding along with it — there’s no org parameter on any tool, so the key or token you hand an agent is the tenant it’s allowed to touch. That fact gets mentioned as a security footnote most places it comes up. It deserves more than a footnote, because it changes what “least privilege” actually means here: there’s no per-tool scope to dial down today, only the credential itself. Which means credential hygiene isn’t a nice extra — it’s the entire access-control surface you have.
What you’re actually scoping
An organization-scoped API key (ak_…) is exactly what it sounds like: a
credential that resolves to one Clerk organization and nothing else. Every
call an agent makes with it — reading a person, drafting a program, launching
a campaign — runs with the full authority that key carries in that org. There
is currently no flag that says “this key can only read” or “this key can only
touch the people namespace.” The org boundary is real and enforced; a
finer-grained boundary inside it isn’t a feature yet.
Given that, the practical question isn’t “how do I scope this key down” — it’s “how do I make sure the blast radius of this key, if it leaks or if the agent misbehaves, is as small and as reversible as I can make it.” Four habits do most of the work.
1. Never hand an agent your own key
It’s tempting to grab whatever ak_… key is already sitting in your password
manager and paste it into an agent config to get moving faster. Don’t. A
personal key is usually the one with the most history behind it — the one
you’ve used in scripts, the one other tools might already reference, the one
you’re least likely to remember to rotate because it’s “just your key.” Handing
it to an agent means every future audit of “what did this agent do” is
tangled up with “what did I do by hand,” and revoking it to contain a problem
takes down everything else that key touches too.
Create a key per agent, per purpose. claude-code-laptop, research-agent-ci,
cursor-dev-sandbox — whatever naming convention you use, make it specific
enough that six months from now you know exactly what breaks if you revoke it,
and exactly what to revoke if that agent starts doing something you didn’t
expect. If you’re setting up one of the common
clients for the first
time, this is the moment to create that key — before you paste anything into
a config file.
2. Match the credential type to how the agent runs
Norbelys’ MCP server accepts two credential shapes, and they have meaningfully different risk profiles — pick based on how the agent actually operates, not by default.
| Org-scoped API key (ak_…) | OAuth 2.1 token | |
|---|---|---|
| Best for | Headless agents, CI, scripts — no human present to sign in | Interactive clients with a real connect flow (Claude's custom connectors, IDE agents you sign into) |
| Lifetime | Long-lived until you revoke it | ~24 hours, then a refresh |
| Attribution | The key — one identity for every call it makes | The signed-in user — writes are attributed to the person, not a shared secret |
| Org selection | Baked in at creation | Chosen at consent, every sign-in |
| Practical risk | Higher — it doesn't expire itself, so a leak stays live until you notice | Lower — a leaked token ages out on its own within a day |
The short version: if a human is present and the client supports it, prefer OAuth — the self-expiry is a guardrail you get for free. Reach for a long-lived API key only when nothing is around to sign in, and treat that key as correspondingly more sensitive because nothing is going to retire it for you.
3. Rotate on a schedule, not on a hunch
A rotation baseline worth adopting
Set a default lifespan for headless keys
Ninety days is a reasonable default for a CI or automation key with no expiry of its own. Put the creation date in the key's name or a tracked note, and treat 'I don't remember when I made this' as a reason to rotate now rather than later.
Rotate immediately on any personnel or tooling change
Someone who set up an agent leaves the team, a CI runner gets rebuilt, a vendor integration is dropped — each of those is a reason to revoke the key that was scoped to that specific setup, not to leave it dangling because it might still be 'fine.'
Treat a paste-and-forget moment as a leak
If a key ever went into a shell command you ran interactively, a chat log, a bug report, or a config file that got committed before you caught it — rotate it. The cost of rotating a key that was never actually exposed is a few minutes. The cost of not rotating one that was is much higher, and you rarely find out which case you're in before it matters.
Revocation is immediate and total: the moment a key is revoked, every agent holding it goes dark on the next call, everywhere. There’s no propagation delay to plan around — which makes rotation cheap enough that “I’m not sure, better safe than sorry” should usually win.
4. Keep the key out of anything that gets committed or logged
The most common leak path isn’t a sophisticated attack — it’s a config file with the header hardcoded that gets checked into a shared repo, or a key that ends up in a CI log because a debug step printed the full request. A few concrete habits close most of that gap:
- Environment variables over hardcoded headers. Reference
$NORBELYS_API_KEYin agent configs where the client supports it, rather than pasting the literal value into a file that might get shared or committed. - Secret managers for CI. If an agent runs in CI, the key belongs in whatever secrets store your CI provider offers, injected at runtime — not in a repo-tracked workflow file.
- Input-variable prompts for editor configs. VS Code’s MCP support, for
one, can prompt for a secret at connect time instead of storing it in
.vscode/mcp.json— worth using specifically because those files are the ones people forget are tracked by git. - Don’t paste keys into the agent’s own chat. It sounds obvious, but a key pasted as plain conversation text with an agent — “here’s my key, use this” — can end up logged wherever that conversation’s history is stored. Configure it at the transport layer (the client’s MCP settings, an env var) instead of the prompt.
One more lever: use a lower-stakes workspace for experiments
Because the organization is the boundary, the cheapest way to cap what an experimental or half-trusted agent setup can reach is to run it against a workspace that has nothing valuable in it yet — no live sending domains, no warmed mailboxes, no real suppression list. Testing a new agent framework or a prompt you’re not fully confident in against a throwaway or staging organization means the worst case, if something calls a tool you didn’t expect, is a mess in a workspace that doesn’t matter — not a real campaign to real inboxes. Once the agent’s behavior is proven out, move the key (a new one, named for its new purpose) to the workspace that actually matters.
None of this requires new product surface — it’s discipline applied to a credential that already does exactly what it’s supposed to. The org boundary Norbelys enforces is real; what you do with the key that carries it is still on you.