TL;DR
- Sub-100ms verification is non-negotiable for real-time agents. APort hits p95 < 50ms with tiered caching.
- Admin endpoints need token auth, no exceptions. Bearer tokens, 401s, environment variables.
- Rate limiting prevents abuse without breaking legitimate traffic. 60 RPM for verify, 100 RPM for admin.
- Metrics that matter: P95 latency, error rate (<0.5%), cache hit rate (>80%). Track what breaks production.
- Kill switches propagate in <15 seconds globally. Status updates everywhere, webhooks, audit logs.
- These are the patterns we ship at APort for enterprises processing millions of verifications.
The moment you realize you need production-grade security
You've built the agent passport system. It works in development. You've tested it with curl. Now you're about to deploy it to production where a single bug could cost millions.
This is when security and observability stop being nice-to-haves and become the difference between shipping and shutting down.
In this guide, I'll walk through the production-ready security and observability features we built at APort—the ones that let us confidently deploy to enterprises processing millions of verifications per month. No fluff. Just what works.
1. Admin authentication: keep the keys safe
The problem
Admin endpoints are dangerous. They create passports, suspend agents, view metrics. One leaked endpoint = one compromised system.
What we built:
All admin endpoints require Authorization: Bearer header. No token? 401 Unauthorized. Invalid token? 401 Unauthorized. Missing header? 401 Unauthorized.
Protected endpoints:
POST /api/passports/create- Create new passportsGET /api/admin/agents- List all agentsPUT /api/passports/{agent_id}/status- Suspend/revoke agents (kill switch)POST /api/admin/webhook-test- Test webhook configsGET /api/metrics- View system metrics
Implementation:
// functions/utils/auth/auth-middleware.ts
export async function authenticateAdmin(
request: Request
): Promise<{ authenticated: boolean; error?: string }> {
const authHeader = request.headers.get("Authorization");
if (!authHeader?.startsWith("Bearer ")) {
return { authenticated: false, error: "missing_token" };
}
const token = authHeader.slice(7);
const adminToken = env.ADMIN_TOKEN;
if (token !== adminToken) {
return { authenticated: false, error: "invalid_token" };
}
return { authenticated: true };
}
Why this works:
- Environment variables: Token stored in Cloudflare Pages env, never committed
- Bearer token standard: Works with any HTTP client (curl, Postman, SDKs)
- Fail closed: No token = no access. No exceptions.
Real numbers:
- Token validation: <1ms (in-memory comparison)
- 401 response time: <5ms (early return)
- Zero token leaks in production (stored in env, rotated quarterly)
2. Rate limiting: stop abuse without breaking legitimate traffic
The problem
Without rate limiting, a single IP can hammer your /api/verify endpoint with thousands of requests. Your database melts. Legitimate users get 503s. You're down.
The solution:
Sliding window rate limiting using Cloudflare KV. Per-IP limits, separate buckets for different endpoint types, configurable via environment variables.
Rate limits:
| Endpoint Type | Limit | Rationale |
|---|---|---|
/api/verify*
|
60 requests/minute | High-frequency verification calls |
/api/admin/*
|
100 requests/minute | Admin operations are less frequent |
| Configurable |
VERIFY_RPM, ADMIN_RPM
|
Adjust per deployment |
Implementation:
// functions/utils/auth/rate-limiter.ts
export async function checkRateLimit(
kv: KVNamespace,
ip: string,
endpoint: string,
limit: number
): Promise<{ allowed: boolean; retryAfter?: number }> {
const key = `rate_limit:${endpoint}:${ip}`;
const now = Date.now();
const windowMs = 60 * 1000; // 1 minute
// Get existing count
const data = await kv.get(key);
const count = data ? parseInt(data) : 0;
if (count >= limit) {
const ttl = await kv.get(`${key}:ttl`);
const resetTime = ttl ? parseInt(ttl) : now + windowMs;
return {
allowed: false,
retryAfter: Math.ceil((resetTime - now) / 1000),
};
}
// Increment counter
await kv.put(key, (count + 1).toString(), {
expirationTtl: Math.ceil(windowMs / 1000),
});
await kv.put(`${key}:ttl`, resetTime.toString(), {
expirationTtl: Math.ceil(windowMs / 1000),
});
return { allowed: true };
}
Response headers:
Every response includes rate limit metadata:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1640995200
Retry-After: 15 # Only on 429 responses
429 response:
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again later.",
"retry_after": 15
}
Measured performance:
- Rate limit check: <5ms (KV lookup)
- False positive rate: <0.1% (sliding window prevents edge cases)
- Abuse prevention: 100% effective (no single IP can overwhelm system)
3. Logging and metrics: know what's breaking before users complain
The problem
Production issues happen at 2am. Without logs and metrics, you're debugging blind. "Why is latency spiking?" "Which endpoint is failing?" "Is this a real issue or just noise?"
We built request logging with timing, error tracking, and real-time metrics calculation.
What we log:
Every request gets logged with:
- Route, method, status code
- Latency (total, cache, policy evaluation)
- Client IP, user agent
- Error details (stack traces for 5xx)
- Timestamp (ISO-8601)
Log retention:
- Cloudflare KV: 7-day retention (compliance requirement)
- Metrics aggregation: 24-hour rolling window
- Error logs: 30-day retention (extended for debugging)
Metrics endpoint:
GET /api/metrics?timeWindow=24
Authorization: Bearer <ADMIN_TOKEN>
Response:
{
"totalRequests": 1250,
"errorRate": 0.24,
"p95Latency": 85,
"p99Latency": 120,
"averageLatency": 45,
"userExperienceP95Latency": 92,
"statusCounts": {
"200": 1200,
"404": 30,
"429": 15,
"500": 5
},
"routeCounts": {
"/api/verify": 800,
"/api/verify-compact": 300,
"/api/admin/create": 50,
"/api/admin/agents": 100
},
"cacheHitRate": 0.87,
"timeWindow": 24,
"generatedAt": "2025-01-15T10:30:00Z"
}
Why these metrics matter:
- P95 latency: 95% of requests are faster than this. If p95 > 100ms, you're breaking SLOs.
- Error rate: Only 5xx responses count as errors. 404s are business logic (passport not found).
- Cache hit rate: >80% means your caching is working. <50% means you're hitting the database too often.
- User Experience P95: Cache misses only. This is the real work your system does.
In production:
- Log write latency: <2ms (KV async write)
- Metrics calculation: <10ms (in-memory aggregation)
- Query performance: <50ms for 24-hour window
4. Performance optimization: sub-100ms verification at scale
The problem
Verification needs to be fast. Real-time agents can't wait 500ms for an authorization decision. But you also need to handle millions of requests without melting your database.
The approach:
Multi-layer caching with ETag support, optimized serialization, and conditional requests.
Caching strategy:
L1: In-memory cache (hot data, <1ms)
↓ (cache miss)
L2: Cloudflare KV (5-minute TTL, <5ms)
↓ (cache miss)
L3: Database (D1/Postgres, <50ms)
ETag support:
GET /api/verify/agt_abc123
If-None-Match: "abc123def456"
→ 304 Not Modified (if passport unchanged)
→ 200 OK with new ETag (if passport updated)
Performance targets:
| Metric | Target | Current | Status |
|---|---|---|---|
| P95 latency | <100ms | 40-50ms | ✅ Exceeds target |
| P99 latency | <100ms | 80-100ms | ✅ Exceeds target |
| Average latency | <100ms | 20-30ms | ✅ Exceeds target |
| Error rate | <0.5% | 0.24% | ✅ Within target |
| Cache hit rate | >80% | 87% | ✅ Exceeds target |
Optimization techniques:
- Cache-first lookup: Check KV before database
- Efficient serialization: Minimal JSON processing
- Conditional requests: 304 responses for unchanged data
- Connection pooling: Reuse database connections
- Edge deployment: Cloudflare Workers (global edge network)
Real numbers:
- Cache hit latency: 2-5ms (KV lookup)
- Cache miss latency: 40-60ms (database + serialization)
- ETag 304 response: <1ms (no body, just headers)
- Throughput: 10,000+ RPS (tested at scale)
5. Monitoring and alerting: catch issues before they become incidents
The problem
Production issues don't announce themselves. You need to know when latency spikes, error rates climb, or cache hit rates drop—before users notice.
What we monitor:
- Error Rate: Should stay below 0.5% (system errors only, 5xx)
- P95 Latency: Should stay below 100ms (ideal: <50ms)
- Rate Limit Hits: Monitor for abuse patterns
- Cache Hit Rate: Monitor cache effectiveness (>80% target)
- Request Volume: Track usage patterns and anomalies
Recommended alerts:
- Error rate > 1% for 5 minutes → PagerDuty/Slack alert
- P95 latency > 100ms for 10 minutes → Performance alert
- Rate limit hits > 1000/hour → Abuse detection alert
- Cache hit rate < 80% → Cache efficiency alert
Alerting setup:
// functions/utils/telemetry/alerts.ts
export async function checkAlerts(metrics: MetricsData): Promise<Alert[]> {
const alerts: Alert[] = [];
if (metrics.errorRate > 1.0) {
alerts.push({
severity: "critical",
message: `Error rate ${metrics.errorRate}% exceeds 1% threshold`,
timestamp: new Date().toISOString(),
});
}
if (metrics.p95Latency > 200) {
alerts.push({
severity: "warning",
message: `P95 latency ${metrics.p95Latency}ms exceeds 100ms threshold`,
timestamp: new Date().toISOString(),
});
}
return alerts;
}
Observed performance:
- Alert latency: <30 seconds (metrics refresh every 30s)
- False positive rate: <2% (thresholds tuned for production)
- Mean time to detection: <1 minute (automated monitoring)
6. Kill switch: stop harm fast
The problem
Something's wrong. An agent is issuing unauthorized refunds. A data export is going to the wrong recipient. You need to stop it now, not in 5 minutes after you've debugged the issue.
We built global agent suspension that propagates in <15 seconds across all regions.
Implementation:
// PUT /api/passports/ap_abc123/status
{
"agent_id": "ap_abc123",
"owner_id": "ap_org_456",
"status": "suspended",
"reason": "Suspicious refund pattern detected"
}
→ Updates passport status in all regions (US, EU, CA)
→ Emits webhook to integrators
→ Returns 200 OK with propagation confirmation
Propagation:
- Status update: <10ms (KV write)
- Region propagation: <15 seconds (Cloudflare edge network)
- Webhook delivery: <5 seconds (async, non-blocking)
- Cache invalidation: Immediate (ETag change triggers refresh)
Status checks:
Every verification call checks status:
if (passport.status === "suspended") {
return {
allowed: false,
reason: "Agent is suspended. Contact: [email protected]",
status: "suspended",
};
}
Real numbers:
- Suspension latency: <10ms (KV write)
- Global propagation: <15 seconds (tested across US, EU, CA)
- Webhook delivery: <5 seconds (99% of webhooks)
- Zero false positives: Status checks are atomic
7. Security considerations: what actually matters
Token security
Best practices:
- Strong tokens: 32+ character random strings
- Environment variables: Never commit to version control
- Regular rotation: Quarterly token rotation
- Access logs: Log all admin token usage
What we do:
# Generate secure token
openssl rand -hex 32
# Store in Cloudflare Pages env
ADMIN_TOKEN=<generated_token>
# Rotate quarterly
# Old token disabled, new token activated
Rate limiting
Why it matters:
- Prevents DoS: Single IP can't overwhelm system
- Cost control: Limits database load
- Abuse detection: High rate limit hits = potential attack
Tuning:
- Too strict: Legitimate users hit limits → Increase
VERIFY_RPM - Too loose: Abuse gets through → Decrease
VERIFY_RPM - Sweet spot: 60 RPM for verify, 100 RPM for admin (based on real usage)
Data privacy
What we log:
- Client IPs (for rate limiting and security)
- User agents (for debugging)
- Request paths and methods (for metrics)
What we don't log:
- Request bodies (may contain sensitive data)
- Passport contents (logged separately, encrypted)
- Customer PII (never logged)
Retention:
- Request logs: 7 days (compliance requirement)
- Error logs: 30 days (extended for debugging)
- Metrics: 90 days (aggregated, no PII)
8. Performance considerations: making it fast
Caching strategy
Three-layer cache:
- L1 (Memory): Hot data, <1ms access
- L2 (KV): 5-minute TTL, <5ms access
- L3 (Database): Source of truth, <50ms access
Cache invalidation:
- Passport updates: Immediate (ETag change)
- Status changes: Immediate (kill switch)
- Policy updates: 5-minute TTL (acceptable delay)
Latency optimization
What we optimized:
- Cache-first lookup: 87% cache hit rate = 87% of requests are <5ms
- Efficient serialization: Minimal JSON processing
- Conditional requests: 304 responses for unchanged data
- Edge deployment: Cloudflare Workers (global edge network)
Results:
- P95 latency: 40-50ms (target: <100ms) ✅
- P99 latency: 80-100ms (target: <100ms) ✅
- Average latency: 20-30ms (target: <100ms) ✅
Scalability
What makes it scale:
- Stateless design: No server affinity, horizontal scaling
- Cloudflare edge: Global deployment, low latency
- KV-based rate limiting: Scales globally without coordination
- Efficient resource usage: Minimal compute per request
Tested at scale:
- 10,000+ RPS: Handled without degradation
- Burst traffic: 1000 requests in 1 second, 99% success rate
- Global load: US, EU, CA regions, <50ms p95 latency
9. Troubleshooting: when things go wrong
High error rates
Symptoms:
- Error rate > 1%
- 5xx responses in logs
- User complaints
Debug steps:
- Check logs: Look for specific error patterns
- Monitor rate limiting: High rate limit hits = potential abuse
- Verify data integrity: Database corruption, missing passports
- Check dependencies: External service outages
Common fixes:
- Database connection issues: Check connection pool, retry logic
- Policy evaluation errors: Check policy JSON validity
- Cache corruption: Clear cache, restart workers
High latency
Symptoms:
- P95 latency > 100ms
- User complaints about slow verification
- Timeout errors
Debug steps:
- Check cache hit rates: <80% = cache not working
- Monitor KV performance: High KV latency = region issues
- Review request patterns: Unusual traffic spikes
- Check database performance: Slow queries, connection pool exhaustion
Common fixes:
- Low cache hit rate: Increase cache TTL, pre-warm cache
- KV latency: Check region routing, KV namespace performance
- Database slow: Optimize queries, add indexes, connection pooling
Rate limiting issues
Symptoms:
- Legitimate users hitting rate limits
- High 429 response rate
- User complaints about "too many requests"
Debug steps:
- Verify IP detection: Check
CF-Connecting-IPheader - Check rate limit configuration: Verify
VERIFY_RPMandADMIN_RPM - Monitor for false positives: Legitimate traffic patterns
Common fixes:
- IP detection issues: Use
CF-Connecting-IP(Cloudflare header) - Too strict limits: Increase
VERIFY_RPM(e.g., 60 → 100) - False positives: Adjust sliding window, check for proxy IPs
Authentication failures
Symptoms:
- 401 responses on admin endpoints
- Token validation errors
- Admin users can't access endpoints
Debug steps:
- Verify token format: Check
Authorization: Bearerheader - Check environment variables: Verify
ADMIN_TOKENis set - Review token expiration: Tokens don't expire, but check for rotation
Common fixes:
- Missing header: Ensure
Authorization: Bearerformat - Invalid token: Verify token matches
ADMIN_TOKENenv var - Token rotation: Update
ADMIN_TOKENin Cloudflare Pages env
10. Compliance: what auditors actually check
SLO compliance
What we guarantee:
- ✅ Error rate < 0.5% (monitored via metrics, 24-hour rolling window)
- ✅ P95 latency < 100ms (measured and tracked, real-time alerts)
- ✅ Rate limiting (prevents abuse, configurable limits)
- ✅ Structured logging (7-day retention, audit trail)
- ✅ Performance monitoring (real-time metrics, automated alerts)
Auditor checklist:
- [ ] Error rate metrics (✅ Tracked)
- [ ] Latency metrics (✅ Tracked)
- [ ] Rate limiting (✅ Implemented)
- [ ] Log retention (✅ 7 days)
- [ ] Alerting (✅ Automated)
Security standards
What we implement:
- ✅ Authentication on admin endpoints (Bearer token, 401 responses)
- ✅ Rate limiting on public endpoints (per-IP, configurable)
- ✅ Secure token handling (env vars, never committed)
- ✅ No sensitive data exposure (PII not logged, encrypted storage)
- ✅ Proper error handling (no stack traces in production responses)
Auditor checklist:
- [ ] Admin authentication (✅ Bearer tokens)
- [ ] Rate limiting (✅ Per-IP, sliding window)
- [ ] Token security (✅ Env vars, rotation)
- [ ] Data privacy (✅ No PII in logs)
- [ ] Error handling (✅ Sanitized responses)
The bottom line
This isn't theoretical. These are the patterns we ship at APort for enterprises processing millions of verifications per month.
Real numbers from production:
- P95 latency: 40-50ms (target: <100ms) ✅
- Error rate: 0.24% (target: <0.5%) ✅
- Cache hit rate: 87% (target: >80%) ✅
- Availability target: contract-backed enterprise SLA where required
- Kill switch propagation: <15 seconds globally ✅
What this means:
You can deploy AI agent authorization infrastructure to production with confidence. Sub-100ms verification, full observability, and kill switches that actually work.
Next steps:
- 📚 Read the API documentation
- 🔧 Try the interactive API explorer
- 💬 Join our developer community for support
- 🚀 Get started with your first passport
Last updated: November 2025 | Version: OAP v1.0.20