Express Middleware
Complete Express.js integration for Agent-Pass authentication with 31 passing tests and production-ready middleware suite.
Quick Start
npm install agent-pass
# or
yarn add agent-pass
# or
pnpm add agent-passimport express from 'express';
import { agentPassMiddleware } from 'agent-pass/express';
const app = express();
// Apply Agent-Pass middleware to protected routes
app.use('/api/agents', agentPassMiddleware({
requireScopes: ['api:access'],
security: {
timeWindow: 300, // 5 minutes
requireFreshNonce: true
},
rateLimits: {
requestsPerMinute: 60
}
}));
// Protected endpoint
app.get('/api/agents/status', (req, res) => {
// req.agent contains verified agent information
const { agent, credential, grantedScopes } = req.agent;
res.json({
success: true,
agent: agent.did,
scopes: grantedScopes
});
});
app.listen(3000);Configuration Options
interface SecurityConfig {
timeWindow: number; // Request validity window (seconds)
requireFreshNonce: boolean; // Require unique nonce per request
allowedOrigins?: string[]; // CORS origins
maxRequestSize?: number; // Max request body size
challengeTimeout?: number; // Challenge expiry (seconds)
}interface RateLimitConfig {
requestsPerMinute: number; // Max requests per minute
burstLimit?: number; // Burst allowance
windowMs?: number; // Time window (ms)
skipSuccessfulRequests?: boolean;
skipFailedRequests?: boolean;
}// Single scope requirement
app.use('/api/data', agentPassMiddleware({
requireScopes: ['data:read']
}));
// Multiple scopes (all required)
app.use('/api/admin', agentPassMiddleware({
requireScopes: ['admin:read', 'admin:write']
}));
// Dynamic scope checking
app.post('/api/process', agentPassMiddleware({
requireScopes: (req) => {
return req.body.type === 'sensitive'
? ['data:read', 'data:process', 'audit:write']
: ['data:read', 'data:process'];
}
}));Advanced Usage
app.use('/api/sensitive', agentPassMiddleware({
requireScopes: ['sensitive:access'],
customValidation: async (credential, request) => {
// Check if agent is from allowed organization
if (!credential.credentialSubject.organization?.includes('trusted-org')) {
throw new Error('Agent not from trusted organization');
}
// Verify additional constraints
const constraints = credential.credentialSubject.constraints;
if (constraints.ipRange && !isIpInRange(request.ip, constraints.ipRange)) {
throw new Error('IP address not allowed');
}
// Check business hours
const now = new Date();
if (now.getHours() < 9 || now.getHours() > 17) {
throw new Error('Access only allowed during business hours');
}
return true;
}
}));Request Lifecycle
Request Parsing
Extract Agent-Pass headers and parse authentication data
Authorization header, challenge, nonce, timestamp validation
Signature Verification
Verify both agent and controller cryptographic signatures
Ed25519 signature validation using public keys from credentials
Credential Validation
Validate credential structure, expiration, and constraints
W3C Verifiable Credentials format, time bounds, scope checks
Scope Authorization
Check if agent has required capabilities for the endpoint
Capability-based access control with fine-grained permissions
Rate Limiting
Apply rate limits and check for abuse patterns
Per-agent rate limiting with configurable windows and bursts
Request Processing
Attach agent context to request and proceed to handler
Populate req.agent with verified agent information
API Reference
Parameters
interface AgentPassConfig {
requireScopes: string[] | ((req: Request) => string[]);
security?: SecurityConfig;
rateLimits?: RateLimitConfig;
customValidation?: (credential: any, request: Request) => Promise<boolean>;
errorHandler?: (error: Error, req: Request, res: Response) => void;
logging?: LoggingConfig;
onAuthSuccess?: (agent: Agent, request: Request) => void;
onAuthFailure?: (error: Error, request: Request) => void;
}Returns
Express middleware function that can be used with app.use() or route-specific middleware
interface AgentRequest extends Request {
agent: {
agent: {
did: string;
name: string;
version: string;
publicKey: string;
};
credential: VerifiableCredential;
grantedScopes: string[];
constraints: {
timeLimit?: string;
ipRange?: string;
rateLimits?: RateLimitConfig;
};
};
}