saturday, september 5, 2026 · the day's ai, attributed published by trilot llc · wyoming
guide · working with ai

Give each agent its own identity, not one shared account

Split the single API key your automations share into one scoped credential per agent, so you can revoke, rotate and attribute each one without breaking the rest.

Published 2026-09-05 · Updated 2026-09-05 · Read 9 min · Reviewed by Rami Steitieh

Verified 2026-09-05 · Rami
on this page · 0 / 0 checked

You started with one API key because it was the fastest way to get the first thing working. It worked, so the second automation used the same key. Now there are six or seven: something that triages your inbox, a drafting assistant wired into your notes, a scheduled job that rewrites listings, two scripts you half remember writing, and whatever your automation platform is doing on a five-minute timer. Every one of them presents the same credential. To every system they touch, they are a single entity with a single set of permissions, and that entity is you.

This is fine until the day you need to answer a question about it. Which of those seven things deleted the row. Whether the key that just leaked into a log file can read your billing data. What breaks if you rotate it right now. A shared credential cannot answer any of those, because it was never designed to distinguish between the things using it. This guide is for solo operators, freelancers and small teams who administer their own tools and have somewhere between two and twenty agents running. If you already have an identity platform, a joiner-mover-leaver process and a written policy on non-human identities, you have a better process than the one described here and should keep using it.

The rule is one credential per agent, and the reasons are boring

Google Cloud’s guidance on service accounts lists the reasons plainly. Sharing one account across multiple applications “can complicate the management of the service account,” because the applications “might have different life cycles” and because over time “the access requirements of applications might diverge,” so you end up granting the shared account access to an increasing number of resources. The recommendation is direct: “Create dedicated service accounts for each application, and avoid using default service accounts” [5].

Substitute “agent” for “application” and nothing changes. Your inbox triage agent needs to read mail. Your listing rewriter needs to write to one database. Neither needs what the other has, but a shared key gives each of them the union of everything any agent has ever needed. That union only grows, because nobody removes a scope from a working key. The permission set becomes an archaeological record of every integration you have ever attempted, and every one of those layers is live.

The third reason is the one that bites hardest in practice. Cloud Audit Logs “include the name of the service account that performed a change or accessed data, but they don’t show the name of the application that used the service account” [5]. The log will faithfully record that your one key did the thing. It cannot tell you which of your seven agents was holding it.

The cost shows up as blast radius, rotation pain and silence

Blast radius is the obvious one. In August 2025, an actor tracked as UNC6395 obtained OAuth tokens connected to the Salesloft Drift application and “systematically exported large volumes of data from numerous corporate Salesforce instances,” from 8 August through at least 18 August. The actor then targeted sensitive credentials in that exported data, specifically Amazon Web Services access keys beginning AKIA, passwords, and Snowflake-related access tokens. Salesloft, working with Salesforce, revoked all active access and refresh tokens for the Drift application on 20 August, and the compromise turned out not to be limited to the Salesforce integration: tokens for the Drift Email integration were used on 9 August to read mail from what Google’s threat intelligence group describes as a very small number of Google Workspace accounts [8]. One integration credential, held broadly, and the exposure was many customers’ data plus whatever secrets happened to be sitting in it.

You are not Salesloft, and your key is not going to be attacked by a named threat cluster. The mechanism still applies at your scale. A single credential that can read your mail, write to your CRM and hit your model provider’s billing endpoint is worth exactly the sum of those things to anyone who gets it, including a prompt-injected agent that gets it legitimately.

Rotation pain is the cost you will actually feel first. The correct response to a possibly-leaked key is to revoke it immediately. With a shared key that means every automation using it stops at once, and you spend the afternoon reconnecting things while your calendar sync is down. That cost is predictable, which means you can price it before you pay it.

Silence is the third cost and the one people underrate. When a shared agent identity does something wrong, you get an outcome without an actor. The row is gone, the email went out, the file is overwritten, and the only thing your logs can tell you is that it was the bot. Debugging then becomes guesswork across every workflow that holds the key, and the fix is usually to disable all of them until the misbehaving one is found by elimination.

Your tools already ship the identity you need

You do not need a new product for this. The controls exist and are usually two menus deep.

On the OpenAI platform, projects are the unit of separation, and a service account “acts as a pseudo-user designed for system access, distinct from individual user accounts.” Service accounts are “only scoped to projects,” and one created at project level is “unique to the project and cannot be used outside of the project they are created in.” Users can also generate a personal API key “that is scoped and limited to accessing that project and its resources,” and set its permission level to All, Restricted or Read Only. Rate limits can be set per model for a project, though “only the Owner of an organization can set and manage project level rate limits” [1].

Anthropic’s equivalent is workspaces. “Every request runs in exactly one workspace and can only access resources within that workspace,” which covers files created through the Files API, message batches and skills. A single-workspace key always runs in the workspace chosen when it was created, while a multi-workspace key runs in whichever workspace each request names in its anthropic-workspace-id header. You get 100 workspaces per organization by default, with archived ones not counting, and each workspace can carry its own spend limit and its own rate limits. Workspace limits can be set lower than the organization’s, never higher [2].

For chat and code, the pattern is the same shape. A Slack app’s bot scopes “grant permissions to your app’s bot user, which acts with its own identity,” and an app “has no access by default. It can only do what its scopes allow” [3]. On GitHub, a fine-grained personal access token is “limited to access resources owned by a single user or organization” and “can be further limited to only access specific repositories for that user or organization,” whereas a classic token will “grant access to all repositories within the organizations that you have access to, as well as all personal repositories in your personal account”; for long-lived integrations GitHub tells you to use a GitHub App instead [4]. In Notion, internal connections “use a static API token” and are tied to one workspace, and access is per-page by construction: “Before a connection can interact with your Notion workspace page(s), the page must be manually shared with the connection” [7].

Every one of those is a place to give an agent its own name and its own ceiling, on a settings screen you already have access to, without adding a product to your stack.

Scope at creation, widen only when something actually fails

The temptation when creating a credential is to grant everything so you never have to come back. Do the opposite, because coming back is cheap and over-granting is not reversible in practice. Start a new agent’s credential with the narrowest permission the platform offers. On the OpenAI platform that is Read Only or Restricted rather than All [1]. On GitHub it is a fine-grained token pointed at the one repository the agent touches [4]. In Notion it is sharing the two pages the agent needs rather than the workspace root [7]. In Slack it is the specific bot scopes for the specific calls, since the app starts with nothing [3].

Then let the failures tell you what to add. Where a platform follows the OAuth pattern, the error names the permission you are missing rather than leaving you to guess. An MCP server handling a request whose token has insufficient scope should return HTTP 403 with a WWW-Authenticate header carrying error="insufficient_scope" and a scope parameter “specifying the minimum scopes needed for the operation” [6]. That response is a free, accurate inventory of what the agent genuinely requires, which is the document you would otherwise have to write by guessing.

The same specification pushes the starting position down on both sides. The scopes_supported field “is intended to represent the minimal set of scopes necessary for basic functionality,” with anything beyond that “requested incrementally through the step-up authorization flow,” and clients “SHOULD follow the principle of least privilege by requesting only the scopes necessary for their intended operations” [6]. Starting small and letting the 403s widen the credential is not a workaround. It is the design.

The one thing worth granting generously is a spend or rate ceiling, because it is a tripwire rather than a permission. A workspace spend limit, which caps monthly spending for that workspace, set just above the agent’s expected cost, will tell you about a runaway loop before your card does [2].

Tokens are supposed to be bound to one destination now

If you are wiring agents to tools through MCP connectors, the specification has already settled the question you might otherwise argue about. In the 2026-07-28 revision, MCP servers “MUST validate that access tokens were issued specifically for them as the intended audience” and “MUST only accept tokens that are valid for use with their own resources.” Servers “MUST NOT accept or transit any other tokens,” and on the other side of the wire, clients “MUST NOT send tokens to the MCP server other than ones issued by the MCP server’s authorization server” [6].

That is the shared-bot-account problem written as a protocol requirement. A token that names its destination can be checked at that destination and is inert anywhere else. A token that names nothing gets accepted everywhere it happens to be recognised, which is precisely the property you re-create each time you paste the same key into a fifth automation.

The practical read for you is a selection rule. When you add a connector or integration, prefer the one that runs an OAuth flow and asks which specific resources it may touch over the one that asks you to paste a long-lived key into a text box. The first produces a credential bound to that connector and that resource. The second produces another copy of your everything key, in another system’s database, with no expiry.

Name the identities so the log can answer the question

Splitting credentials only pays off if you can tell them apart afterwards, which means the naming is part of the work, not an afterthought. Give each credential the name of the job, not the person or the tool: inbox-triage-read, listings-writer, calendar-sync. When a log line shows up six months later, that string is the entire investigation.

Attribution has a hard floor you should know about. Google Cloud’s guidance also says to “Use service account keys only when there is no viable alternative,” partly because keys create a non-repudiation problem: when a service account authenticates with a key, “there is no reliable way to tell who used the key” [5]. So a static API key, however well named, tells you which agent role acted, not which human or process held the secret. That is a large improvement over one shared key and still not proof of anything. If your platform offers short-lived tokens or an app-based install rather than a pasted secret, take it.

Two other levers make the log useful without any extra tooling. Per-project rate limits on the OpenAI platform and per-workspace spend and rate limits on Anthropic’s give each agent its own ceiling instead of a share of one, so a misbehaving agent hits its own wall first [1][2]. And GitHub “automatically removes personal access tokens that haven’t been used in a year,” which quietly cleans up the credentials you forgot [4]. Expiry is attribution’s cheap cousin: a credential that dies on its own cannot become an unexplained log line in 2028.

checklist
Splitting one shared credential into per-agent identities
0 of 8 · saved in this browser only
calculator
What one shared key costs you to rotate
h / year

automations × minutes × rotations, in hours. This is the recurring cost only; it excludes the downtime while each automation is disconnected. Computed in the page; nothing is sent anywhere.

What still goes wrong

Splitting credentials does not reduce what any single agent can do, and the agent with the broadest job is still the one that can cause the most damage. If your drafting agent needs write access to the same database your rewriter needs, giving them separate keys means you can revoke one without the other, and nothing more. Per-agent identity is a containment and attribution improvement. It is not a capability limit, and it does not defend against an agent that is doing exactly what you authorized on instructions it should not have followed.

The second failure is drift back to the shared key. In three months you will build something at 11pm and reach for a credential that already exists rather than making a new one, and the new agent will inherit permissions it does not need. The only defence is the inventory file in the checklist, and it only works if updating it is part of shipping rather than a task you intend to do later. Small teams lose this one more often than they lose the initial migration.

Third, some tools genuinely do not support this. Plenty of smaller SaaS products still issue exactly one API key per account, with no scopes, no expiry and no way to distinguish callers. When that is the case, the honest answer is that the tool is the limit, not your process. Put the single-key integrations in their own list, keep them away from anything holding customer data, and treat the vendor’s support for scoped tokens as a real criterion the next time you are choosing between two products.

sources
  1. 01OpenAI — Managing your work in the API platform with projectshelp.openai.com
  2. 02Anthropic — Workspaces (Claude Platform docs)platform.claude.com
  3. 03Slack — Scopes referencedocs.slack.dev
  4. 04GitHub — Managing your personal access tokensdocs.github.com
  5. 05Google Cloud — Best practices for using service accountsdocs.cloud.google.com
  6. 06Model Context Protocol 2026-07-28 — Authorizationmodelcontextprotocol.io
  7. 07Notion — Authorization (internal and public connections)developers.notion.com
  8. 08Google Threat Intelligence — Data theft from Salesforce instances via Salesloft Driftcloud.google.com
next guide
Being small stopped being a defence
10 min · verified 2026-09-05
related guides