We are racing into the era of autonomous AI agents, but our security models remain stuck in the past. Today, when you hook an AI assistant up to your Gmail, calendar, or internal corporate Slack, you are likely handing over your personal API token or a massive OAuth scope. The agent acts on your behalf by pretending to be you. Giving an AI agent a CEO's credentials is a security nightmare. If the agent goes off the rails or suffers from a prompt injection, the attacker gains your full system access. To fix this, Paola Estefania and Bereket Habtemeskel from Better Auth introduced the Agent Auth protocol. This protocol establishes a new security paradigm: treating AI agents as first-class, independent principals with their own identities, public-private key pairs, and fine-grained capabilities. The Core Pillars of Agent Security The Agent Auth framework solves three fundamental problems in agent-to-service communication: * **Discovery**: How does an agent dynamically learn what actions it is allowed to take on a target service without relying on hardcoded system prompts? * **Authorization (Capabilities)**: Moving away from broad OAuth "scopes" (like a blanket `gmail.readonly`) to granular "capabilities" that restrict agents to highly specific tools. * **Identity & Traceability**: Equipping each agent with its own cryptographic identity (a private key) so that services can log, audit, and revoke individual agents without disconnecting the human user. Instead of acting as a transparent proxy that intercepts all data traffic, the architecture relies on a lightweight directory model. The directory matches an agent's intent to specific exposed capabilities, making the protocol highly scalable and privacy-preserving. Prerequisites To implement and follow this guide, you should be familiar with: * Basic identity and authentication concepts (OAuth, OpenID Connect). * Writing and structure of OpenAPI specifications. * The Model Context Protocol (MCP) by Anthropic for connecting agents to local tools. * Node.js or Python for SDK implementation. Mapping APIs to Agent Capabilities Because most of the web runs on REST APIs rather than native agent protocols, the Agent Auth protocol uses a translation layer. It ingests standard OpenAPI schemas and translates endpoints into discrete agent capabilities. Here is an example of how a service translates its HTTP endpoints into a clean, machine-readable JSON capability list that an agent can discover: ```json { "issuer": "https://api.mailservice.com/well-known/agent-configuration", "capabilities": [ { "id": "cap:emails:read", "name": "Read Last Email", "description": "Allows the agent to retrieve the most recent incoming email", "endpoint": "/api/v1/emails/latest", "method": "GET" }, { "id": "cap:emails:send", "name": "Send Email", "description": "Allows the agent to send an email on your behalf", "endpoint": "/api/v1/emails/send", "method": "POST", "constraints": { "rate_limit": "5_per_hour" } } ] } ``` By exposing this configuration at a `.well-known` endpoint, the agent can programmatically query what actions are possible on the host system. This mirrors how OpenID Connect handles client configuration discovery. Cryptographic Identity and Device Flow Auth To make an agent a distinct principal, the Agent Auth SDK forces the agent to generate an asymmetric key pair. When the agent wants to perform an action, it does not send your raw session cookie. Instead, it requests a token signed with its private key. When an agent attempts to execute a capability, the protocol kicks off a back-channel authorization process (often using a device-style flow) to get explicit user approval: ```javascript import { AgentClient } from '@agent-auth/sdk'; // Initialize the agent with its own cryptographic identity const agent = new AgentClient({ agentId: 'agent_email_reader_v1', privateKey: process.env.AGENT_PRIVATE_KEY, directoryUrl: 'https://directory.agentauth.com' }); async function fetchLatestEmails() { // Request authorization to execute a specific capability const authorization = await agent.requestCapability('cap:emails:read'); if (authorization.status === 'pending') { console.log(`User approval required. Please approve request code: ${authorization.userCode}`); // The SDK handles back-channel polling or prompts a device flow login await authorization.pollUntilApproved(); } if (authorization.status === 'approved') { // Execute the signed, metered request against the target service const emails = await agent.execute('cap:emails:read', { token: authorization.accessToken }); console.log('Emails retrieved safely:', emails); } } ``` When executing this code, the backend verifies that the signed token originated from the specific agent ID `agent_email_reader_v1` on behalf of the user, logging the exact cryptographic footprint of that interaction. Revoking Compromised Agents What happens when an agent starts exhibiting unexpected behavior? Under the old credential-sharing model, you would have to revoke your entire API key, breaking every other integration. With Agent Auth, you target the specific agent principal. When you revoke an agent via the directory dashboard, its unique token signing keys are blacklisted. The next time the agent tries to verify its signature against your resource server, the validation step fails instantly: ```javascript // Inside the Resource Server verification middleware async function verifyAgentRequest(req, res, next) { const authHeader = req.headers['x-agent-signature']; const { agentId, token } = parseSignature(authHeader); // Check the revocation status of this specific agent ID const isRevoked = await directory.checkRevocationStatus(agentId); if (isRevoked) { return res.status(401).json({ error: 'agent_revoked', message: 'This agent identity has been terminated by the resource owner.' }); } // Proceed to verify cryptographic token signature const isValid = verifySignature(token, agentId); if (!isValid) { return res.status(403).json({ error: 'invalid_agent_signature' }); } next(); } ``` Syntax and Design Conventions * **Intent Matching vs. Hard Proxies**: Do not route actual payloads through a centralized authentication proxy. The proxy acts purely as a directory matching intents to capabilities, keeping the communication architecture decentralized. * **User-Agent Pairing**: The protocol design specifies that an agent ID is always cryptographically linked to a user ID. An agent cannot exist as a completely detached entity; it must always resolve back to a human supervisor. * **Back-Channel Authorization (CIBA)**: The protocol relies heavily on asynchronous back-channel authorization. This allows the agent to request permissions in the background while the user approves or denies them via a separate, secure UI channel. Practical Implementations * **Enterprise Tool Delegation**: Granting customer service AI agents the capability to issue refunds, capped at $50 per transaction, without giving them access to general accounting tools. * **Local Developer Assistants**: Running an MCP-compatible terminal agent inside tools like Cursor or Claude, restricted strictly to executing reads within a designated workspace directory. * **Cross-Service Workflows**: Allowing an AI travel assistant to check flight availability on an external API and propose drafts in your email client without having delete privileges on your inbox. Tips and Pitfalls * **The Re-auth UX Trap**: Prompting users for approval on every single read operation will ruin the user experience. Developers should set logical boundaries, auto-approving read actions while flagging destructive actions (like deletes or financial transactions) for manual confirmation. * **Handling Ephemeral Keys**: Agents frequently spin up and down. Maintain clean key-rotation policies on the server side to prevent a buildup of orphaned public keys in your active directory databases. * **Securing the Agent's Private Key**: Ensure the agent's private key is stored securely within the hosting environment's secure enclave or hardware security module, rather than hardcoding it into the agent's prompt context window.
OpenAPI
Products
Jul 2024 • 1 videos
High activity month for OpenAPI. ArjanCodes among the most active voices, with 1 videos across 1 sources.
Mar 2026 • 1 videos
High activity month for OpenAPI. Laravel Daily among the most active voices, with 1 videos across 1 sources.
Apr 2026 • 2 videos
High activity month for OpenAPI. AI Engineer and Laravel Daily among the most active voices, with 2 videos across 2 sources.
Jun 2026 • 1 videos
High activity month for OpenAPI. Laravel Daily among the most active voices, with 1 videos across 1 sources.
Jul 2026 • 1 videos
High activity month for OpenAPI. AI Engineer among the most active voices, with 1 videos across 1 sources.
ArjanCodes (1 mention) labels OpenAPI the industry-standard specification for RESTful designs in "6 Easy Tips to Design an AWESOME REST API," and Laravel Daily (2 mentions) showcases automated documentation generation through the Scramble package in "Laravel 13 Demo."
- 4 days ago
- Jun 19, 2026
- Apr 20, 2026
- Apr 19, 2026
- Mar 31, 2026
Overview Designing a REST API involves more than just selecting a framework or hosting on a cloud provider. A truly great API acts as a seamless interface that developers enjoy using, yet even major tech companies often fail at basic usability. This guide explores the architectural decisions and best practices that transform a functional API into a professional-grade product, focusing on standards, consistency, and the implementation of advanced features like metadata merging. Prerequisites To get the most out of this tutorial, you should have a solid grasp of **Python**, basic **HTTP methods** (GET, POST, etc.), and the fundamentals of **JSON**. Familiarity with **FastAPI** and **SQLAlchemy** will help when we dive into the code walkthrough for custom data handling. Key Libraries & Tools * OpenAPI: The industry-standard specification for describing and documenting RESTful APIs. * FastAPI: A modern, high-performance Python web framework that automatically generates OpenAPI schemas. * SQLAlchemy: A powerful Python SQL Toolkit and ORM used here to manage database models. * Pydantic: Data validation and settings management using Python type annotations. Mastering Standards and Consistency Standards provide a shared vocabulary between the provider and the consumer. Adopting the OpenAPI specification allows you to generate interactive documentation automatically. This transparency reduces the friction of integration. Beyond documentation, adherence to REST naming conventions—using plural nouns like `/customers` instead of singular `/customer`—creates a predictable environment. Consistency is the hallmark of a mature API. If your `/orders` endpoint returns a `payer_id`, your `/invoices` endpoint should not suddenly switch to calling that same entity a `recipient` without an ID. Map out your resource relationships early. Ensure that pagination, error handling, and date formats remain uniform across every single endpoint. Code Walkthrough: Implementing Stripe-Style Metadata One of the most powerful features for third-party integration is the ability to store custom metadata. This allows users to link your resources to IDs in their other systems (like an accounting ID or a CRM link). The Base Model with Custom Data Magic In this implementation, we use SQLAlchemy and Pydantic to create a base class that handles "merge" logic for metadata, similar to the Stripe API. ```python import json from sqlalchemy.orm import declarative_base from pydantic import BaseModel, validator class BaseCustomData: def update_custom_data(self, new_data: dict): # 1. Load existing stringified JSON from the DB current_data = json.loads(self.custom_data or "{}") # 2. Iterate and merge logic for key, value in new_data.items(): if value is None: current_data.pop(key, None) # Unset if value is null else: current_data[key] = value # Merge new key-values # 3. Save back as string self.custom_data = json.dumps(current_data) ``` Explanation of the Logic * **The Merge Operation**: Instead of overwriting the entire `custom_data` field, the method loads the existing JSON, updates specific keys, and preserves others. This prevents accidental data loss during partial updates. * **The Null Deletion Pattern**: By checking if a value is `None`, the API follows the convention where sending `{"my_key": null}` explicitly removes that key from the database. * **Serialization**: We store the data as a string in the database for compatibility but expose it as a dictionary in the API layer for ease of use. Syntax Notes & Best Practices When defining field names, stick to `snake_case`. It is significantly more readable than mashing words together. Furthermore, utilize sensible defaults for arguments. If a user searches for transactions, default the `end_date` to the current time rather than forcing them to provide it. This reduces the cognitive load on the developer using your tool. Tips & Gotchas * **Version Your API**: Always include the version in the URL (e.g., `/v1/`) to prevent breaking changes for existing users. * **Clear Error Bodies**: Don't just return a 400 error. Provide a JSON response body explaining *why* the request failed. * **Navigation**: Ensure resources are interconnected. An order object should include a link or ID for the customer, and vice-versa. Avoid creating "data islands" where resources cannot be reached from related objects.
Jul 19, 2024