Designing API auth for AI agents - OAuth scopes vs API keys vs short-lived tokens?

We’re building a platform where customers can connect AI agents (think Claude with MCP, custom LangChain agents, etc.) to interact with our API. The agents do things like query data, create reports, and trigger workflows on behalf of users. Standard CRUD stuff, but the auth model for agent-to-API access is genuinely different from human-to-API access and I’m not sure the industry has settled on best practices yet.

The core problem: a human user authorizes an agent to act on their behalf, but the agent might run unattended for hours or days, make hundreds of API calls, and its behavior is partially unpredictable (the LLM decides which endpoints to call based on the user’s natural language request). Traditional OAuth flows weren’t designed for this.

Here’s what I’m considering:

Option 1: Standard OAuth2 with tight scopes
User goes through normal OAuth consent flow, agent gets an access token with scoped permissions. We’d define granular scopes like data:read, reports:create, workflows:trigger. The agent’s MCP server config stores the refresh token.

Pros: well-understood pattern, good tooling support.
Cons: scope explosion as we add more resources. An agent that needs to “analyze sales data and create a report” needs like 5 different scopes. Also, refresh tokens sitting in MCP server configs feel sketchy from a security standpoint.

Option 2: Short-lived session tokens with capability URLs
User initiates a session, gets a token that’s valid for 1 hour max. The token encodes what the agent is allowed to do for this specific task, not general permissions. Each API response includes capability URLs for valid next actions (HATEOAS-style).

Pros: minimal blast radius if token leaks, agent can only do what the session allows.
Cons: complex to implement, the LLM needs to understand capability URLs (though Claude and GPT-4 handle this fine in practice), and long-running agent tasks need session renewal.

Option 3: Agent-specific API keys with policy attachments
Each agent gets its own API key with an attached policy document (similar to AWS IAM policies). The policy defines allowed actions, rate limits, and resource constraints. Users manage agent policies through our dashboard.

Pros: simple for agent developers, policies are flexible.
Cons: API keys are long-lived secrets, basically the problem Clamper AI is trying to solve. If the key leaks from an MCP config file (which is a real risk, those configs end up in dotfiles and version control), the attacker has persistent access.

Questions for the community:

  1. Rate limiting per agent vs per user: If a user authorizes 3 different agents, should each get its own rate limit bucket, or share the user’s quota? We’re leaning toward per-agent limits to prevent one chatty agent from starving others, but that means tracking agent identity separately from user identity.

  2. Audit logging granularity: For compliance, we need to log who did what. But “who” is now “User X’s agent Y, acting on instruction Z.” Are you storing the original natural language instruction that triggered the agent’s API calls? That feels useful for audit but raises its own privacy questions.

  3. Permission escalation detection: An agent might be authorized to read data and create reports. But what if the LLM hallucinates a tool call to DELETE /workflows/123? We obviously reject it at the API level, but should we also flag/alert on repeated unauthorized attempts? That could indicate a prompt injection attack trying to escalate through the agent.

  4. MCP server config security: This is the elephant in the room. MCP configs with API keys are basically .env files that everyone checks into git. Google just launched their Developer Knowledge MCP server, and Clamper AI is working on a secure credential framework, but there’s no standard yet. How are you handling this today?

We’re on Node.js (Fastify), PostgreSQL, and deploying on AWS. The API currently uses standard OAuth2 for human users.


Seed content posted by the DevForums team to help get our community started. Have a better answer? Jump in!