{"_id":"@aporthq/middleware-express","_rev":"2-a309492bda197ea3ed01ce75a8a3631a","name":"@aporthq/middleware-express","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@aporthq/middleware-express","version":"0.1.0","keywords":["agent-passport","express","middleware","authentication","verification","aport","mcp","policy-enforcement"],"author":{"name":"APort Team","email":"team@aport.io"},"license":"MIT","_id":"@aporthq/middleware-express@0.1.0","maintainers":[{"name":"uchi4jah","email":"uchi.uchibeke@gmail.com"}],"homepage":"https://aport.io","bugs":{"url":"https://github.com/aporthq/agent-passport/issues"},"dist":{"shasum":"be1ca12c7e7038893aef5c7b777126675d9137b8","tarball":"https://registry.npmjs.org/@aporthq/middleware-express/-/middleware-express-0.1.0.tgz","fileCount":19,"integrity":"sha512-XFUQ2xbir4x+0GmleIVdiwIMfe2Jmvnh3+gXb7sB5FFYE43+Rx8o63FYCQcO1ygeyXthgadwY/LfHqp9QkFLTQ==","signatures":[{"sig":"MEUCIQDEpSoW0DsDiFCFav5oZLeMbPHaSs4GV/VgU437TTRtDAIgaPx0EHvVjdE6Io4AMQCErIiYt7l4H3tm3g5OnuvGodI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85563},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"e89d47ffcfd0446260c02c5d37a9d5f7420fc35b","scripts":{"dev":"tsc --watch","test":"jest","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"uchi4jah","email":"uchi.uchibeke@gmail.com"},"repository":{"url":"git+https://github.com/aporthq/agent-passport.git","type":"git","directory":"middleware/express"},"_npmVersion":"11.5.2","description":"Express.js middleware for The Passport for AI Agents","directories":{},"_nodeVersion":"20.17.0","dependencies":{"express":"^4.18.0","@aporthq/sdk-node":"^0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","ts-jest":"^29.4.1","supertest":"^6.3.0","typescript":"^5.0.0","@types/jest":"^29.5.14","@types/node":"^20.19.17","@types/express":"^4.17.0","@types/supertest":"^2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/middleware-express_0.1.0_1761504298267_0.7229230561731663","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aporthq/middleware-express","version":"0.1.1","description":"Express.js middleware for The Passport for AI Agents","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","dev":"tsc --watch","prepublishOnly":"npm run build"},"keywords":["agent-passport","express","middleware","authentication","verification","aport","mcp","policy-enforcement"],"author":{"name":"APort Team","email":"team@aport.io"},"license":"MIT","dependencies":{"@aporthq/sdk-node":"^0.1.0","express":"^4.18.0"},"devDependencies":{"@types/express":"^4.17.0","@types/jest":"^29.5.14","@types/node":"^20.19.17","@types/supertest":"^2.0.0","jest":"^29.7.0","supertest":"^6.3.0","ts-jest":"^29.4.1","typescript":"^5.0.0"},"repository":{"type":"git","url":"git+https://github.com/aporthq/agent-passport.git","directory":"middleware/express"},"homepage":"https://aport.io","bugs":{"url":"https://github.com/aporthq/agent-passport/issues"},"publishConfig":{"access":"public"},"_id":"@aporthq/middleware-express@0.1.1","gitHead":"7958e3bb56760dff0de9d6dab70f789a517b03b1","_nodeVersion":"20.17.0","_npmVersion":"11.5.2","dist":{"integrity":"sha512-wE69I+p8J56746PMZ7Z6p5hLqS5vLr+GdLh5pEWCp5ZF4pyrWbIBarwmTn+wCK5BEjs/i+Nzcyz9roUwdnui3w==","shasum":"7223312fbfbae6214816fd4c3b522431053374cf","tarball":"https://registry.npmjs.org/@aporthq/middleware-express/-/middleware-express-0.1.1.tgz","fileCount":19,"unpackedSize":85563,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDvJ5zAPwwp7gldr0nDG2+kHGNJJ+HsLf83XWmloUYQGQIhAPWL1YPXdi2Gtj5vIDQlkhcnJwZ0HFSKzu66cwTdypc7"}]},"_npmUser":{"name":"uchi4jah","email":"uchi.uchibeke@gmail.com"},"directories":{},"maintainers":[{"name":"uchi4jah","email":"uchi.uchibeke@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/middleware-express_0.1.1_1763510807846_0.9745545818887464"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-26T18:44:58.177Z","modified":"2025-11-19T00:06:48.210Z","0.1.0":"2025-10-26T18:44:58.469Z","0.1.1":"2025-11-19T00:06:48.024Z"},"bugs":{"url":"https://github.com/aporthq/agent-passport/issues"},"author":{"name":"APort Team","email":"team@aport.io"},"license":"MIT","homepage":"https://aport.io","keywords":["agent-passport","express","middleware","authentication","verification","aport","mcp","policy-enforcement"],"repository":{"type":"git","url":"git+https://github.com/aporthq/agent-passport.git","directory":"middleware/express"},"description":"Express.js middleware for The Passport for AI Agents","maintainers":[{"name":"uchi4jah","email":"uchi.uchibeke@gmail.com"}],"readme":"# Agent Passport Middleware - Express\n\nExpress middleware for The Passport for AI Agents verification and policy enforcement.\n\n## Installation\n\n```bash\nnpm install @aporthq/middleware-express\n```\n\n## Getting Started\n\n**Key Facts:**\n\n- **Agent ID Required**: Every policy check needs an agent ID\n- **Two Options**: Pass agent ID as function parameter (preferred) or use `X-Agent-Passport-Id` header\n- **Resolution Priority**: Function parameter > Header > Fail with 401\n- **Registry**: Defaults to `https://aport.io` (configurable)\n- **Policies**: Choose from `finance.payment.refund.v1`, `data.export.create.v1`, `messaging.message.send.v1`, `code.repository.merge.v1`\n\n| **Method** | **Agent ID Source** | **Security** | **Use Case** |\n|------------|-------------------|--------------|--------------|\n| **Explicit Parameter** | Function argument | ✅ Highest | Production, explicit control |\n| **Header Fallback** | `X-Agent-Passport-Id` | ⚠️ Medium | Backward compatibility |\n| **Global Middleware** | `X-Agent-Passport-Id` | ⚠️ Medium | All routes, same policy |\n\n## Quick Start\n\n### 1. Global Policy Enforcement\n\n```javascript\nconst express = require('express');\nconst { agentPassportMiddleware } = require('@aporthq/middleware-express');\n\nconst app = express();\napp.use(express.json());\n\n// Enforce specific policy globally\napp.use(agentPassportMiddleware({\n  policyId: \"finance.payment.refund.v1\",  // Enforces refunds policy\n  failClosed: true\n}));\n\n// All routes now require finance.payment.refund.v1 policy compliance\napp.post('/api/refunds', (req, res) => {\n  // Policy already verified - safe to process\n  const { amount, currency } = req.body;\n  res.json({ \n    success: true, \n    refund_id: `ref_${Date.now()}`,\n    agent_id: req.agent.agent_id \n  });\n});\n```\n\n### 2. Route-Specific Policy Enforcement\n\n```javascript\nconst { requirePolicy } = require('@agent-passport/middleware-express');\n\nconst AGENT_ID = \"ap_a2d10232c6534523812423eec8a1425c45678\"; // Your agent ID\n\n// Explicit agent ID (preferred)\napp.post('/api/refunds', \n  requirePolicy(\"finance.payment.refund.v1\", AGENT_ID),\n  (req, res) => {\n    // Policy verified with explicit agent ID\n    res.json({ success: true });\n  }\n);\n\n// Header fallback\napp.post('/api/export', \n  requirePolicy(\"data.export.create.v1\"),  // Uses X-Agent-Passport-Id header\n  (req, res) => {\n    // Policy verified via header\n    res.json({ success: true });\n  }\n);\n```\n\n### 3. Multiple Policies\n\n```javascript\n// Different policies for different routes\napp.post('/api/refunds', \n  requirePolicy(\"finance.payment.refund.v1\", AGENT_ID),\n  (req, res) => res.json({ message: \"Refund processed\" })\n);\n\napp.post('/api/data/export', \n  requirePolicy(\"data.export.create.v1\", AGENT_ID),\n  (req, res) => res.json({ message: \"Export created\" })\n);\n\napp.post('/api/messages/send', \n  requirePolicy(\"messaging.message.send.v1\", AGENT_ID),\n  (req, res) => res.json({ message: \"Message sent\" })\n);\n```\n\n## API Reference\n\n### `agentPassportMiddleware(options)`\n\nGlobal middleware that enforces a specific policy on all routes.\n\n**Parameters:**\n\n- `options.policyId` (string): Policy ID to enforce (e.g., \"finance.payment.refund.v1\")\n- `options.failClosed` (boolean): Fail if agent ID missing (default: true)\n- `options.baseUrl` (string): Registry base URL (default: \"https://aport.io\")\n- `options.timeout` (number): Request timeout in ms (default: 5000)\n\n**Returns:** Express middleware function\n\n### `requirePolicy(policyId, agentId?)`\n\nRoute-specific middleware that enforces a specific policy.\n\n**Parameters:**\n\n- `policyId` (string): Policy ID to enforce (e.g., \"finance.payment.refund.v1\")\n- `agentId` (string, optional): Explicit agent ID (preferred over header)\n\n**Returns:** Express middleware function\n\n**Agent ID Resolution:**\n\n1. Function parameter (if provided)\n2. `X-Agent-Passport-Id` header (fallback)\n3. Fail with 401 error (if neither provided)\n\n### `requirePolicyWithContext(policyId, context, agentId?)`\n\nRoute-specific middleware with custom context.\n\n**Parameters:**\n\n- `policyId` (string): Policy ID to enforce\n- `context` (object): Custom context data\n- `agentId` (string, optional): Explicit agent ID\n\n**Returns:** Express middleware function\n\n## Request Object\n\nAfter successful policy verification, the request object contains:\n\n```javascript\napp.post('/api/refunds', requirePolicy(\"finance.payment.refund.v1\", AGENT_ID), (req, res) => {\n  // req.agent - Verified agent passport data\n  console.log(req.agent.agent_id);        // \"ap_a2d10232c6534523812423eec8a1425c45678\"\n  console.log(req.agent.assurance_level); // \"L2\"\n  console.log(req.agent.capabilities);    // [\"finance.payment.refund\"]\n  \n  // req.policyResult - Policy evaluation result\n  console.log(req.policyResult.evaluation.decision_id);\n  console.log(req.policyResult.evaluation.remaining_daily_cap);\n});\n```\n\n## Available Policies\n\n### finance.payment.refund.v1\n\n- **Capabilities:** `[\"finance.payment.refund\"]`\n- **Assurance:** L2 minimum\n- **Fields:** `order_id`, `customer_id`, `amount_minor`, `currency`, `region`, `reason_code`, `idempotency_key`\n- **Rules:** Currency support, region validation, reason code validation, idempotency handling\n- **Amount Format:** `amount_minor` must be in cents (e.g., `500` for $5.00)\n\n### data.export.create.v1\n\n- **Capabilities:** `[\"data.export\"]`\n- **Assurance:** L1 minimum\n- **Fields:** `rows`, `format`, `contains_pii`\n- **Rules:** Row limits, PII handling\n\n### messaging.message.send.v1\n\n- **Capabilities:** `[\"messaging.send\"]`\n- **Assurance:** L1 minimum\n- **Fields:** `channel`, `message_count`, `mentions`\n- **Rules:** Rate limits, channel restrictions\n\n### code.repository.merge.v1\n\n- **Capabilities:** `[\"repo.pr.create\", \"repo.merge\"]`\n- **Assurance:** L2 minimum\n- **Fields:** `repository`, `base_branch`, `pr_size_kb`\n- **Rules:** Repository access, branch protection, PR size limits\n\n## Error Handling\n\nThe middleware returns appropriate HTTP status codes:\n\n```javascript\n// 401 - Missing or invalid agent ID\n{\n  \"error\": \"missing_agent_id\",\n  \"message\": \"Agent ID is required. Provide it as X-Agent-Passport-Id header.\"\n}\n\n// 403 - Policy violation\n{\n  \"error\": \"policy_violation\",\n  \"message\": \"Policy violation\",\n  \"agent_id\": \"ap_a2d10232c6534523812423eec8a1425c45678\",\n  \"policy_id\": \"finance.payment.refund.v1\"\n}\n\n// 400 - Field validation failed\n{\n  \"error\": \"field_validation_failed\",\n  \"message\": \"Field validation failed: Required field 'order_id' is missing\"\n}\n```\n\n## TypeScript Support\n\n```typescript\nimport express, { Request, Response } from 'express';\nimport { \n  agentPassportMiddleware, \n  requirePolicy,\n  AgentRequest \n} from '@agent-passport/middleware-express';\n\nconst app = express();\n\n// Global policy enforcement\napp.use(agentPassportMiddleware({\n  policyId: \"finance.payment.refund.v1\",\n  failClosed: true\n}));\n\n// Route-specific policy enforcement\napp.post('/api/refunds', \n  requirePolicy(\"finance.payment.refund.v1\", \"ap_a2d10232c6534523812423eec8a1425c45678\"),\n  (req: AgentRequest, res: Response) => {\n    // Type-safe access to agent data\n    const agentId = req.agent.agent_id;\n    const policyResult = req.policyResult;\n    \n    res.json({ success: true, agent_id: agentId });\n  }\n);\n```\n\n## Setup & Agent ID Options\n\n### Key Setup Facts\n\n1. **Agent ID is Required**: Every policy check needs an agent ID\n2. **Two Ways to Provide Agent ID**:\n   - **Explicit Parameter** (preferred): Pass agent ID directly to function\n   - **Header Fallback**: Use `X-Agent-Passport-Id` header\n3. **Resolution Priority**: Function parameter > Header > Fail\n4. **Registry URL**: Defaults to `https://aport.io` (configurable)\n5. **Policy Enforcement**: Happens automatically on all protected routes\n\n### Agent ID Resolution Examples\n\n```javascript\n// ✅ EXPLICIT AGENT ID (Most Secure)\nconst AGENT_ID = \"ap_a2d10232c6534523812423eec8a1425c45678\";\napp.post('/api/refunds', \n  requirePolicy(\"finance.payment.refund.v1\", AGENT_ID),  // Agent ID in function\n  handler\n);\n\n// ✅ HEADER FALLBACK (Backward Compatible)\napp.post('/api/export', \n  requirePolicy(\"data.export.create.v1\"),  // No agent ID - uses header\n  handler\n);\n// Client sends: X-Agent-Passport-Id: ap_a2d10232c6534523812423eec8a1425c45678\n\n// ✅ GLOBAL MIDDLEWARE (Uses Header)\napp.use(agentPassportMiddleware({\n  policyId: \"finance.payment.refund.v1\"  // Agent ID from X-Agent-Passport-Id header\n}));\n```\n\n### Environment Variables\n\n```bash\n# Registry base URL (optional)\nAGENT_PASSPORT_BASE_URL=https://aport.io\n\n# Default agent ID for development (optional)\nAGENT_PASSPORT_AGENT_ID=ap_a2d10232c6534523812423eec8a1425c45678\n```\n\n### Skip Paths\n\n```javascript\napp.use(agentPassportMiddleware({\n  policyId: \"finance.payment.refund.v1\",\n  skipPaths: [\"/health\", \"/metrics\", \"/status\"]\n}));\n```\n\n## Examples\n\n### E-commerce Refund System\n\n```javascript\nconst express = require('express');\nconst { requirePolicy } = require('@agent-passport/middleware-express');\n\nconst app = express();\napp.use(express.json());\n\nconst AGENT_ID = \"ap_a2d10232c6534523812423eec8a1425c45678\";\n\n// Refund processing with policy enforcement. Amount in cents (100 = $1.00)\napp.post('/api/refunds', \n  requirePolicy(\"finance.payment.refund.v1\", AGENT_ID),\n  (req, res) => {\n    const { amount, currency, order_id, customer_id, reason_code } = req.body;\n    \n    // Policy already verified - safe to process\n    const refund_id = `ref_${Date.now()}`;\n    \n    res.json({\n      success: true,\n      refund_id,\n      amount,  // Amount in cents\n      currency,\n      order_id,\n      customer_id,\n      reason_code,\n      agent_id: req.agent.agent_id\n    });\n  }\n);\n```\n\n### Data Export System\n\n```javascript\n// Data export with policy enforcement\napp.post('/api/data/export', \n  requirePolicy(\"data.export.create.v1\", AGENT_ID),\n  (req, res) => {\n    const { rows, format, contains_pii } = req.body;\n    \n    // Policy verified - safe to export\n    const export_id = `exp_${Date.now()}`;\n    \n    res.json({\n      success: true,\n      export_id,\n      rows,\n      format,\n      contains_pii,\n      agent_id: req.agent.agent_id\n    });\n  }\n);\n```\n\n### Messaging System\n\n```javascript\n// Messaging with policy enforcement\napp.post('/api/messages/send', \n  requirePolicy(\"messaging.message.send.v1\", AGENT_ID),\n  (req, res) => {\n    const { channel, message_count, mentions } = req.body;\n    \n    // Policy verified - safe to send\n    const message_id = `msg_${Date.now()}`;\n    \n    res.json({\n      success: true,\n      message_id,\n      channel,\n      message_count,\n      mentions,\n      agent_id: req.agent.agent_id\n    });\n  }\n);\n```\n\n## License\n\nMIT\n\n---\n\n**Last Updated**: 2025-01-16 00:00:00 UTC\n","readmeFilename":"README.md"}