DEV Community

Custodia-Admin
Custodia-Admin

Posted on • Originally published at pagebolt.dev

How to Manage API Keys and Credentials in AI Agent Workflows

How to Manage API Keys and Credentials in AI Agent Workflows

Your agent needs to call an API. The API requires authentication. So you give the agent your API key.

Then you realize: The agent now has permanent, unaudited access to that service.

If the agent is compromised, the attacker has your credentials. If the agent drifts and makes unexpected calls, those calls are traced back to you. If the agent is hijacked mid-session, it's acting with your full privileges.

This is the credential management problem every team hits when deploying agents at scale.

The Naive Approach (And Why It Fails)

Most teams start here:

agent = AIAgent()
agent.set_api_key("sk-prod-1234567890abcdef")
agent.execute(task="call_stripe_api")
Enter fullscreen mode Exit fullscreen mode

The agent has your Stripe key. It can create charges, refund transactions, delete customers. Permanently. Unaudited.

This works until:

  • The agent gets hijacked by prompt injection
  • A vulnerability in the agent runtime is exploited
  • The agent drifts and makes unintended calls
  • You need to audit what the agent accessed

Then you realize: you have no fine-grained control, no audit trail, no way to revoke access without breaking the agent.

The Right Approach: Credential Wrapping

Instead of giving the agent the actual key, give it a wrapped credential that enforces constraints:

class ConstrainedCredential:
    def __init__(self, api_key, constraints):
        self.api_key = api_key
        self.constraints = constraints
        self.audit_log = []

    def call_api(self, method, endpoint, params):
        # Check constraints before allowing the call
        if not self.is_allowed(method, endpoint, params):
            raise PermissionError(f"Call blocked by policy: {method} {endpoint}")

        # Log the call for audit
        self.audit_log.append({
            "timestamp": now(),
            "method": method,
            "endpoint": endpoint,
            "params": sanitize(params)
        })

        # Make the actual API call
        return make_api_call(self.api_key, method, endpoint, params)

    def is_allowed(self, method, endpoint, params):
        """Check if this call matches the credential's constraints."""
        allowed_methods = self.constraints.get("methods", [])
        allowed_endpoints = self.constraints.get("endpoints", [])
        rate_limit = self.constraints.get("rate_limit", None)

        # Validate method
        if method not in allowed_methods:
            return False

        # Validate endpoint
        if not any(endpoint.startswith(ep) for ep in allowed_endpoints):
            return False

        # Check rate limits
        if rate_limit and self.exceeds_rate_limit():
            return False

        return True
Enter fullscreen mode Exit fullscreen mode

Now the agent gets a credential that can only:

  • Call specific endpoints (e.g., only POST /charges, not DELETE /customers)
  • Use specific HTTP methods (e.g., only POST, not GET with query parameters)
  • Stay within rate limits (e.g., max 10 calls/minute)
  • Is fully audited (every call is logged)

Practical Implementation

When setting up an agent with Stripe access:

stripe_credential = ConstrainedCredential(
    api_key="sk-prod-1234567890abcdef",
    constraints={
        "methods": ["POST"],
        "endpoints": ["/charges", "/refunds"],
        "rate_limit": "10_calls_per_minute",
        "max_amount": 10000  # Max $100 per charge
    }
)

agent = AIAgent()
agent.set_stripe_credential(stripe_credential)
agent.execute(task="process_refunds_for_order_123")
Enter fullscreen mode Exit fullscreen mode

Now if the agent is compromised:

  • It can't call any endpoint it wasn't explicitly allowed to call
  • It can't exceed the rate limit
  • It can't make charges over $100
  • Every call is logged and auditable

Key Patterns

1. Principle of Least Privilege
Give the agent only the permissions it needs, nothing more.

2. Time-Bounded Credentials
Credentials that expire after N hours, requiring refresh. Limits the window of compromise.

3. Action-Specific Credentials
Different credentials for different tasks. An agent that processes refunds gets a different key than one that creates charges.

4. Audit Everything
Every credential use is logged with timestamp, parameters, outcome. Non-repudiation.

5. Revoke Instantly
If an agent is compromised, revoke its credential without affecting other agents.

Getting Started

  1. Audit your current agents — what credentials do they have?
  2. Map their actual needs — which API calls does each agent actually make?
  3. Create constrained credentials — with least-privilege policies
  4. Wrap legacy credentials — gradually migrate from bare keys to wrapped credentials
  5. Log everything — every API call the agent makes is audited

Agents are powerful. Giving them unrestricted access is a liability. Wrapping credentials with constraints is the baseline security practice.


Try it free: 100 requests/month on PageBolt—capture visual proof of every API call and agent action. No credit card required.

Top comments (0)