Agent to Product
FeaturesLong read

Scoped API Keys for Per-User Agent Sandboxes

Scoped credentials let per-user agent sandboxes actually isolate from each other.

Columnist · · 12 min read
Cover illustration for “Scoped API Keys for Per-User Agent Sandboxes”
Features · September 2, 2026 · 12 min read · 2,674 words

Every user gets their own agent, but almost nobody wires the credentials right on the first pass. The default move is one shared agent running on one shared API key, with every user's requests passing through the same string of characters. That setup demos fine, but it falls apart the moment two users hit the platform at once, and the failure mode is always the same: nobody scoped the key, so nothing about the architecture actually knows the users apart.

Here's what breaks first. One user's action bleeds into another's session or data, because the key can't tell them apart in the first place. A single compromised credential exposes every user at once, there's no way to tell which user did what, since every action traces back to the same key, and no way to cut off one bad actor without shutting the whole thing down for everyone else.

Going from "one agent for the team" to "one agent per user" is a credential question before it's an infrastructure one. Scoping the keys is what makes per-user isolation mean something at the access layer. Skip that step, and the rest of the sandbox architecture is decoration.

What a scoped API key actually is, and what it controls

An API key, at its core, is a credential that tells a service who's calling it. Scoping adds three constraints on top of that.

Bounded permissions: the key can call specific operations, not everything the service offers. Bounded identity: the key stands in for one user, one tenant, or one agent instance, not the whole application. Bounded lifetime: the key expires or gets shut off on its own, without touching any other key in the system.

Compare that to a typical application-level key, one credential handing full application privilege to whoever holds it, with no per-user limit and nothing to stop a single call from doing more than it should. That's where privilege accumulation creeps in. Reuse the same key across enough agent tasks, and the agent ends up holding more authority than any single task needs, because nobody drew a line to stop it. Scoping draws that line along three axes: what actions the key can take, whose identity it acts under, and how long it lives before it needs renewal.

Worth saying plainly: scoped keys are only part of the job, and they don't replace filesystem isolation or network isolation. Those are separate layers, and all of them have to hold at once.

The credential risks that make scope non-optional in agentic systems

Agents burn through credentials by nature. Every API call, every file write, every third-party integration needs its own form of authentication, and each one is a place where something can go wrong.

Start with the exfiltration surface. Credentials sitting inside an agent's runtime can be read out of environment variables, config files, the prompt context itself, or anything the agent generates along the way.

Prompt injection makes this worse, and it's the sharper risk of the two. An attacker plants instructions inside a document, a webpage, or a tool response the agent processes, and those instructions tell the agent to hand over its own credentials or step outside the job it was given. Community plugin ecosystems carry a similar risk: install a bad third-party tool into the agent's runtime, and it inherits whatever permissions that runtime already holds. A broad key means a bigger blast radius the moment something malicious slips in.

Then there's the headcount problem. On a multi-user agent platform, machine identities outnumber human ones by a wide margin, so one leaked credential ripples across a huge population of running instances, not just one account.

Token expiry causes its own trouble, separate from scoping but tangled up with it. An agent running continuously might try to refresh the same token from several concurrent tool calls at once, and the result is a silent failure with no clean error to point to. Give each instance its own token, one instance to one token, and that race condition disappears on its own.

Under deadline pressure, developers still hardcode credentials straight into config files or prompts, a habit that shows up constantly in public code repositories. AI-assisted coding tools make it worse: they'll happily reproduce a hardcoded secret right along with the rest of the generated code, because they're pattern-matching, not auditing.

How scoped keys map onto a per-user sandbox architecture

Think in three layers: the operator running the platform, the user the agent works for, and the agent instance, the sandbox actually doing the work.

The operator holds a platform-level key used only to create and manage sandboxes. That key never gets passed into an agent's runtime, full stop, no exceptions for convenience. Each agent instance instead holds its own narrow credential, tied to that instance alone, with its own filesystem, its own integrations, its own token lifecycle running independent of every other instance.

Provisioning follows the same shape every time. One API call spins up an isolated sandbox, and that sandbox gets its own scoped credentials at the moment of creation, not inherited from whatever key the operator happens to be holding at the time.

Enforcing isolation at the key level buys three things directly. Revoking one user cuts off only that user's key, and nobody else notices. Every action in the audit trail maps back to a specific user's credential, giving a precise account of what happened rather than a vague sense that "the agent did it." And a compromised sandbox can't turn around and use its key against some other sandbox's resources, because the key was never scoped to reach that far.

Integration credentials follow the same pattern. When a user connects Gmail or Slack, that OAuth grant gets stored against their instance specifically, never shared with the operator and never shared with other users.

Ramp's engineering team built a financial agent internally on exactly this logic: separate, short-lived environments per agent task, each with its own access to internal engineering tools, specifically so one task's actions can't leak into another's. That's the architecture holding up under a real workload.

"Sandboxed" carries more underneath the credential piece. Filesystem isolation, where each instance gets its own disk. Network isolation, so a request from one sandbox can't carry another sandbox's credentials to some other endpoint. And process isolation at the kernel level, the kind gVisor provides, so one instance's crash or compromise can't reach into another's memory space.

Scoped keys vs. OAuth tokens — when each model fits

Neither model wins outright, and treating this as a pick-one decision is the mistake. Both have a real job on an agent platform; the trick is not confusing the jobs.

OAuth is the right call for third-party integrations, Gmail, Slack, GitHub, since those services already speak OAuth natively. It's also right for per-user authorization within those services: OAuth scopes let an agent read contacts without being able to delete them, and each grant can be pulled back for one user without touching anyone else's connection. Token rotation is baked into the protocol itself, which kills the long-lived-credential problem before it starts.

Scoped API keys fit a different slot: platform-to-sandbox authentication, where the operator is provisioning an instance or the agent runtime is calling internal platform APIs. They also fit anywhere an OAuth flow doesn't work, background jobs, headless agents, CLI agents running with no browser in sight. For service-to-service calls inside the sandbox, a short-lived, rotated key does the job without the overhead of a full OAuth handshake.

Most production platforms run both: OAuth for user-facing integration grants, scoped keys for platform and internal calls. The real difference shows up in lifecycle management. OAuth has revocation and per-grant invalidation built into the protocol, but API keys don't come with that for free; they usually need global rotation unless the platform goes out of its way to build per-key revocation on top. That capability is worth demanding from any hosting layer a builder picks, because it doesn't show up by accident, and platforms that skip it are the ones where "revoke this one user" turns into "rotate the key and break everyone."

The rule underneath all of it: any credential an agent uses to act on a user's behalf has to trace back to that user's explicit grant, and it has to be revocable without dragging anyone else's access down with it.

Credential injection: keeping secrets out of prompts and artifacts

Passing a credential through a prompt is tempting because it's fast and it works, right up until it doesn't. It's also one of the most avoidable mistakes in this entire list, which is exactly why it keeps happening.

Prompt-carried credentials show up in conversation logs and context windows, readable by anyone with log access. They're a direct target for prompt injection, since an attacker just needs the agent to repeat or forward what it's already holding. And they end up baked into generated artifacts too, committed code, exported files, task outputs, which turns a one-time leak into a permanent one sitting in a repository somewhere, indexed and searchable.

The right injection surface is environment variables set when the sandbox is created, or a secrets mount. Neither shows up in the prompt context, and neither is readable from anything the user actually sees.

There's a placeholder technique worth knowing. Everything inside the sandbox, including anything the agent installs or pulls down at runtime, sees only an opaque placeholder standing in for the real credential. The platform resolves that placeholder into the actual key at the network boundary, so the agent calls the service it needs without the real credential ever sitting anywhere readable inside the sandbox.

That same rule applies to config files like a CLAUDE.md or any instructions handed to the agent, and no credentials belong there, not even as a placeholder example, because examples get copied.

Here's the blunt version of the audit implication: if a credential can appear in a log or a generated artifact, eventually it will. The architecture has to make that outcome impossible, not just unlikely, and "unlikely" is not a security posture.

Managing integration credentials across many user sandboxes

Every sandbox needs its own live connections to whatever third-party apps the user relies on. Keeping token refresh, revocation, and scope straight across hundreds or thousands of users is a real engineering problem, not a small one, and it's the part most teams underestimate until it's already broken in production.

Start with expiry. Google access tokens run out after an hour, Slack tokens carry their own separate rotation limits, and any agent running long enough hits one of these mid-task. The failure usually shows up silently, with no clear error pointing at what went wrong.

Concurrency adds another wrinkle. An agent making several tool calls at once might try to refresh the same token from more than one thread at the same time. Give every instance its own separate token store, and that race condition can't happen, since no two instances ever share a token to begin with.

An integration platform layer exists to take this off the operator's plate: running the OAuth flows, refreshing tokens on a schedule before they expire, managing the credential lifecycle for every connection. That way the operator isn't rebuilding this logic for every single app they support.

Authorization has to stay per-agent too. When a user connects Gmail or Slack through a branded interface, that grant gets stored against their instance specifically, not against the operator's account, and the operator never sees the user's raw credentials at any point.

Revocation has to scale the same way. A user disconnects an integration, or cancels their account, and only their tokens get pulled. Nobody else's connection is touched, and that revocation has to actually propagate through the integration layer, not sit as a flag somewhere unread.

Worth stating flatly: a big integration catalogue, thousands of connected apps, is a vanity number if the credential management underneath it isn't built per-instance. A long list of supported integrations backed by a shared credential model multiplies the exact risk described above rather than adding capability.

What builders need from a hosting platform to make this work

Operators who run their own infrastructure pay a real tax for it, building per-sandbox key generation, rotation, revocation, secrets injection, and integration token lifecycle from scratch. None of that work has anything to do with what the agent is actually supposed to do for the user, and every week spent on it is a week not spent on the product.

A hosting platform worth using handles a specific set of things without being asked twice. Per-instance credentials get provisioned the moment a sandbox spins up, and secrets get injected through the environment, never through the prompt. Filesystem and process isolation happen at the kernel level, not as an application-level convention that one bug quietly breaks. Spend caps sit on each sandbox individually, so one compromised instance can't run up a bill that drains everyone else's budget. Per-instance integration authorization comes with token refresh handled behind the scenes, invisibly, before anything expires.

For operators shipping a branded, white-label product to their own customers, the platform's own credentials need to stay completely out of sight from end users. The hosting layer's authentication model has to support a clean split between operator, user, and instance on its own terms, not as an afterthought bolted onto a single-tenant system built for something else.

A good test for whether a platform actually gets this right: spinning up a new user sandbox, complete with its own credentials, its own disk, its own integration connections, should take one API call, not a sequence of manual infrastructure steps strung together by whoever's on call that week.

Per-instance isolation is also what makes an audit trail worth reading. When every action ties back to one scoped key for one specific user instance, the logs mean something concrete, and that specificity is what holds up in an incident review. Platforms that handle gVisor-level isolation, per-instance spend caps, integrated token management, and carry something like SOC 2 certification take this whole category of work off an operator's desk. That's the practical case for managed infrastructure over self-hosting, once per-user sandboxing is the actual goal and not just a slide in the deck.

Putting it together: the scoped-key checklist for a production per-user agent product

At the credential design layer: every sandbox gets its own credential, never shared across users. Keys get scoped to the minimum set of operations that instance actually needs, no broad application-level keys ever passed into a runtime, and every key carries an expiry and a rotation schedule. A key that never expires is a misconfiguration waiting to be found by someone who isn't on the team.

At the injection layer: credentials enter through environment variables or secrets mounts, never through a prompt, a task file, or anything committed to a repository, and it's worth actually checking that credentials can't surface in generated artifacts, conversation logs, or exported files.

At the integration layer: OAuth grants for third-party services stay per-instance, stored and revocable at the individual user level, and token refresh runs automatically and ahead of expiry, so agents never hit a silent failure from a token that ran out mid-task.

At the isolation layer: filesystem isolation holds, so one user's disk stays unreadable from another user's sandbox, and a compromised instance's credential can't authenticate against another instance's endpoints, full stop, no exceptions carved out for edge cases.

At the operational layer: spend caps sit on every sandbox, so a runaway or compromised instance can't drain the operator's balance, and revoking one user's access happens instantly and touches nobody else. Audit logs map every action to a specific scoped key; a vague "the agent did it" entry is a sign the credential model isn't granular enough yet, not a sign the incident was unusual.

Scoped keys work best as a design decision made early, before the first user signs up, rather than retrofitted after the first credential leak forces the question. That timing determines whether "per-user" actually means something.

Sources

  1. nango.dev
  2. workos.com
  3. firecrawl.dev
  4. scalekit.com
  5. agenta.ai
  6. cosmonic.com