Integrate AgentDoor into your Express.js API in just 3 lines of code. The @agentdoor/express adapter provides middleware that handles agent discovery, registration, authentication, and request enrichment.
Installation
npm install @agentdoor/express @agentdoor/core
Quick Start
Import AgentDoor
Import the agentdoor middleware from @agentdoor/express:import express from "express";
import { agentdoor } from "@agentdoor/express";
Configure and mount
Add the AgentDoor middleware to your Express app:const app = express();
app.use(express.json());
app.use(
agentdoor({
scopes: [
{
id: "data.read",
description: "Read application data",
price: "$0.001/req",
rateLimit: "1000/hour",
},
{
id: "data.write",
description: "Write application data",
price: "$0.01/req",
rateLimit: "100/hour",
},
],
pricing: {
"data.read": "$0.001/req",
"data.write": "$0.01/req",
},
rateLimit: { requests: 1000, window: "1h" },
})
);
Access agent context
Use req.isAgent and req.agent in your route handlers:app.get("/api/data", (req, res) => {
if (req.isAgent) {
console.log(`Agent ${req.agent.id} with scopes: ${req.agent.scopes}`);
}
res.json({ data: "hello" });
});
app.listen(3000);
Complete Example
Here’s a full working example with agent authentication:
import express from "express";
import { agentdoor } from "@agentdoor/express";
const app = express();
app.use(express.json());
// AgentDoor middleware
app.use(
agentdoor({
scopes: [
{
id: "weather.read",
description: "Read current weather data",
price: "$0.001/req",
rateLimit: "1000/hour",
},
{
id: "weather.forecast",
description: "7-day weather forecasts",
price: "$0.01/req",
rateLimit: "100/hour",
},
],
pricing: {
"weather.read": "$0.001/req",
"weather.forecast": "$0.01/req",
},
rateLimit: { default: "1000/hour" },
x402: {
network: "base",
currency: "USDC",
paymentAddress: process.env.X402_WALLET || "0xYourWalletAddress",
},
})
);
// Your API routes
app.get("/api/weather", (req, res) => {
const city = (req.query.city as string) || "san-francisco";
if (req.isAgent) {
console.log(`Agent ${req.agent.id} requested weather for ${city}`);
}
res.json({
city,
temp: 62,
condition: "foggy",
timestamp: new Date().toISOString(),
requestedBy: req.isAgent ? `agent:${req.agent.id}` : "human",
});
});
app.listen(3000, () => {
console.log("Server running on http://localhost:3000");
console.log("Discovery: http://localhost:3000/.well-known/agentdoor.json");
});
How It Works
The agentdoor() middleware automatically:
- Mounts discovery endpoint:
GET /.well-known/agentdoor.json
- Mounts registration endpoints:
POST /agentdoor/register (step 1: get challenge)
POST /agentdoor/register/verify (step 2: verify signature)
- Mounts auth endpoint:
POST /agentdoor/auth (returning agents)
- Mounts health check:
GET /agentdoor/health
- Enriches requests: Adds
req.isAgent and req.agent to all subsequent requests
Advanced Configuration
Custom Storage Backend
By default, AgentDoor uses an in-memory store. For production, use a persistent store:
import { agentdoor } from "@agentdoor/express";
import { SQLiteStore } from "@agentdoor/core";
const store = new SQLiteStore("./agents.db");
app.use(
agentdoor({
scopes: [/* ... */],
store, // Use persistent storage
})
);
Disable Auth Guard
If you want to manually control which routes require agent auth:
app.use(
agentdoor({
scopes: [/* ... */],
enableAuthGuard: false, // Don't auto-verify requests
})
);
// Manually apply auth guard to specific routes
import { createAuthGuard } from "@agentdoor/express";
const authGuard = createAuthGuard(store, jwtSecret);
app.use("/api/protected/*", authGuard);
Webhooks & P1 Features
Enable webhooks, reputation gates, and spending caps:
app.use(
agentdoor({
scopes: [/* ... */],
// Webhooks
webhooks: {
endpoints: [{ url: "https://hooks.example.com/agentdoor" }],
secret: process.env.WEBHOOK_SECRET,
},
// Reputation
reputation: {
gates: [
{ minReputation: 30, action: "block" },
{ minReputation: 50, action: "warn" },
],
},
// Spending caps
spendingCaps: {
defaultCaps: [
{ amount: 10, currency: "USDC", period: "daily", type: "hard" },
],
},
})
);
Request Enrichment
AgentDoor enriches Express requests with agent context:
declare global {
namespace Express {
interface Request {
agent: {
id: string;
publicKey: string;
scopes: string[];
metadata: Record<string, string>;
rateLimit: { requests: number; window: string };
} | null;
isAgent: boolean;
}
}
}
API Reference
agentdoor(options)
Creates an Express Router with all AgentDoor routes and auth guard.
Options:
scopes (required): Array of scope definitions
pricing: Price per scope (e.g., { "data.read": "$0.001/req" })
rateLimit: Default rate limit config
x402: X402 payment config (network, currency, paymentAddress)
store: Custom agent store (defaults to MemoryStore)
enableAuthGuard: Auto-apply auth guard to all routes (default: true)
enableBodyParser: Auto-parse JSON bodies on AgentDoor routes (default: true)
webhooks: Webhook configuration
reputation: Reputation gates configuration
spendingCaps: Spending caps configuration
Returns: Express Router instance
createAuthGuard(store, secret)
Creates a standalone auth guard middleware for manual route protection.
Parameters:
store: Agent store instance
secret: JWT secret for token validation
Returns: Express middleware function
TypeScript Support
The package includes full TypeScript definitions. Import types:
import type {
AgentDoorExpressOptions,
AgentContext,
ScopeDefinition,
} from "@agentdoor/express";
The auth guard middleware does not block unauthenticated requests. It only enriches requests with agent context. Your route handlers decide access policy.
Next Steps