AI Agent Authentication and Access Control

body{font-family:-apple-system,BlinkMacSystemFont,’Segoe UI‘,Roboto,sans-serif;max-width:900px;margin:0 auto;padding:2rem;line-height:1.7;color:#1a1a1a}
h1{color:#1a1a1a;border-bottom:3px solid #6366f1;padding-bottom:.5rem}
h2{color:#334155;margin-top:2rem}
h3{color:#475569}
code{background:#f1f5f9;padding:.2rem .5rem;border-radius:4px;font-size:.9em}
pre{background:#1e293b;color:#e2e8f0;padding:1.5rem;border-radius:8px;overflow-x:auto;font-size:.9em}
blockquote{border-left:4px solid #6366f1;padding-left:1rem;color:#64748b;font-style:italic}
table{border-collapse:collapse;width:100%;margin:1rem 0}
th,td{border:1px solid #e2e8f0;padding:.75rem;text-align:left}
th{background:#f8fafc}
.tag{display:inline-block;background:#e0e7ff;color:#4338ca;padding:.2rem .6rem;border-radius:999px;font-size:.85em;margin-right:.5rem}

AI Agent Authentication and Access Control

Reviewed: June 4, 2026

Published: May 26, 2026 | Reading time: 10 min | AI Security Authentication Access Control

As AI agents become first-class citizens in production systems, they need the same authentication and authorization controls as human users — but with additional constraints unique to autonomous systems.

Why Agent Auth is Different

Traditional API authentication assumes a human is on the other end. AI agents operate autonomously, make thousands of decisions per minute, and chain tool calls in unpredictable ways. This creates unique security challenges:

Architecture: Agent Identity System

Give every agent a unique, verifiable identity:

import uuid
import hashlib
import secrets
from datetime import datetime, timedelta

class AgentIdentity:
    """Issue and manage cryptographic identities for AI agents."""
    
    def __init__(self, agent_name: str, owner: str, scopes: list[str]):
        self.agent_id = f"agent-{uuid.uuid4().hex[:12]}"
        self.agent_name = agent_name
        self.owner = owner
        self.scopes = scopes
        self.api_key = secrets.token_hex(32)
        self.created_at = datetime.utcnow()
        self.is_active = True
    
    def get_auth_headers(self) -> dict:
        return {
            "Authorization": f"Bearer {self.api_key}",
            "X-Agent-ID": self.agent_id,
            "X-Agent-Name": self.agent_name,
            "X-Agent-Owner": self.owner
        }
    
    def can(self, scope: str) -> bool:
        return scope in self.scopes and self.is_active
    
    def revoke(self):
        self.is_active = False

# Create an agent with minimal required scopes
agent = AgentIdentity(
    agent_name="support-agent-v2",
    owner="team-support@datagate.ch",
    scopes=["tickets:read", "tickets:write", "knowledge:read"]
)
print(f"Agent ID: {agent.agent_id}")
print(f"Scopes: {agent.scopes}")
# Agent ID: agent-a1b2c3d4e5f6
# Scopes: ['tickets:read', 'tickets:write', 'knowledge:read']

API Key Management for Agents

class APIKeyManager:
    """Manage API keys with rotation, scoping, and revocation."""
    
    def __init__(self):
        self.keys = {}  # key_hash -> key_metadata
    
    def issue_key(self, agent_id: str, scopes: list[str], ttl_hours: int = 720) -> str:
        raw_key = f"dk_{secrets.token_hex(32)}"
        key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
        
        self.keys[key_hash] = {
            "agent_id": agent_id,
            "scopes": scopes,
            "issued_at": datetime.utcnow(),
            "expires_at": datetime.utcnow() + timedelta(hours=ttl_hours),
            "last_used": None,
            "use_count": 0,
            "is_active": True
        }
        return raw_key  # Return once — never stored in plaintext
    
    def validate_key(self, raw_key: str, required_scope: str) -> dict:
        key_hash = hashlib.sha256(raw_key.encode()).hexdigest()
        meta = self.keys.get(key_hash)
        
        if not meta or not meta["is_active"]:
            return {"valid": False, "reason": "Key not found or revoked"}
        
        if datetime.utcnow() > meta["expires_at"]:
            return {"valid": False, "reason": "Key expired"}
        
        if required_scope not in meta["scopes"]:
            return {"valid": False, "reason": f"Scope '{required_scope}' not granted"}
        
        meta["last_used"] = datetime.utcnow()
        meta["use_count"] += 1
        
        return {
            "valid": True,
            "agent_id": meta["agent_id"],
            "scopes": meta["scopes"]
        }
    
    def rotate_key(self, old_raw_key: str) -> str:
        """Rotate key — issue new one, invalidate old."""
        key_hash = hashlib.sha256(old_raw_key.encode()).hexdigest()
        meta = self.keys[key_hash]
        
        # Issue new key with same scopes
        new_key = self.issue_key(meta["agent_id"], meta["scopes"])
        
        # Revoke old key
        meta["is_active"] = False
        
        return new_key

Rate Limiting for Agents

import time
from collections import defaultdict

class AgentRateLimiter:
    """Per-agent rate limiting with burst allowance."""
    
    def __init__(self, requests_per_minute: int = 60, burst: int = 10):
        self.rpm = requests_per_minute
        self.burst = burst
        self.windows = defaultdict(list)  # agent_id -> [timestamps]
    
    def check(self, agent_id: str) -> dict:
        now = time.time()
        minute_ago = now - 60
        
        # Clean old entries
        self.windows[agent_id] = [
            t for t in self.windows[agent_id] if t > minute_ago
        ]
        
        current_rate = len(self.windows[agent_id])
        
        if current_rate >= self.rpm + self.burst:
            return {
                "allowed": False,
                "retry_after": 60 - (now - self.windows[agent_id][0]),
                "current_rate": current_rate
            }
        
        self.windows[agent_id].append(now)
        
        return {
            "allowed": True,
            "remaining": self.rpm + self.burst - current_rate - 1,
            "reset_in": 60 - (now - self.windows[agent_id][0]) if self.windows[agent_id] else 60
        }

OAuth2 for Agent-to-Agent Communication

For agent-to-agent communication, use OAuth2 client credentials flow:

# Agent receives a short-lived access token via OAuth2
import requests

class AgentOAuth2Client:
    """OAuth2 client credentials flow for agent authentication."""
    
    def __init__(self, client_id: str, client_secret: str, token_url: str):
        self.client_id = client_id
        self.client_secret = client_secret
        self.token_url = token_url
        self._access_token = None
        self._token_expires = 0
    
    def get_token(self) -> str:
        if self._access_token and time.time()  dict:
        token = self.get_token()
        resp = requests.post(
            f"https://api.datagate.ch/agents/{target_agent_id}/invoke",
            json=payload,
            headers={"Authorization": f"Bearer {token}"}
        )
        return resp.json()

Audit Logging Requirement

Every agent action should be logged with full context:

import json
import uuid

class AgentAuditLog:
    """Immutable audit log for agent actions."""
    
    def __init__(self):
        self.entries = []
    
    def log(self, agent_id: str, action: str, resource: str, 
            result: str, metadata: dict = None):
        entry = {
            "id": str(uuid.uuid4()),
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "agent_id": agent_id,
            "action": action,
            "resource": resource,
            "result": result,
            "metadata": metadata or {},
        }
        self.entries.append(entry)
        # In production: write to append-only log (e.g., CloudWatch, BigQuery)
        print(json.dumps(entry))
    
    def query_by_agent(self, agent_id: str) -> list[dict]:
        return [e for e in self.entries if e["agent_id"] == agent_id]
    
    def query_suspicious(self) -> list[dict]]:
        return [e for e in self.entries if e["result"] in ("denied", "error", "rate_limited")]

Security Checklist for Agent Auth

Check Priority
Each agent has unique cryptographic identity Critical
API keys regularly rotated (90 days max) High
Principle of least privilege for all scopes Critical
Rate limiting enforced per-agent High
All actions logged with agent attribution High
Revocation mechanism tested and documented Critical
OAuth2 for inter-agent communication Medium
Credential storage uses vault (not env vars) High

Part of the AI Agent Security series on DataGate.ch.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert