Skip to content

DCP-AI + Express Quick Start

Verify DCP signed bundles in your Express.js APIs using the @dcp-ai/express middleware.


Installation

npm install @dcp-ai/express @dcp-ai/sdk express

How DCP Integrates with Express

The DCP Express middleware extracts and verifies signed bundles from incoming requests. Verified agent identity is attached to the request object for downstream use.

Client (AI Agent)                    Express Server
  │                                      │
  │─── Request + DCP Bundle ────────────►│
  │    (X-DCP-Bundle header              │
  │     or body.signed_bundle)           │
  │                                      ├─ dcpVerify() middleware
  │                                      │  ├─ Parse bundle (V1 or V2)
  │                                      │  ├─ Verify signatures
  │                                      │  ├─ Check session binding
  │                                      │  ├─ Optional revocation check
  │                                      │  └─ Attach req.dcpAgent
  │                                      │
  │◄── Response ────────────────────────│

Complete Working Example

import express from 'express';
import { dcpVerify, type DCPAgent } from '@dcp-ai/express';

const app = express();
app.use(express.json());

// 1. Basic DCP verification — require a valid bundle on all /api routes
app.use('/api/*', dcpVerify({ requireBundle: true }));

// 2. Access verified agent identity in your handlers
app.get('/api/data', (req: express.Request & { dcpAgent?: DCPAgent }, res) => {
  const agent = req.dcpAgent!;

  res.json({
    message: `Hello, agent ${agent.agentId}`,
    humanPrincipal: agent.humanId,
    capabilities: agent.capabilities,
    riskTier: agent.riskTier,
    dcpVersion: agent.dcpVersion,
  });
});

// 3. Capability-based access control
app.post('/api/payments', (req: express.Request & { dcpAgent?: DCPAgent }, res) => {
  const agent = req.dcpAgent!;

  if (!agent.capabilities.includes('payments')) {
    return res.status(403).json({
      error: 'Agent lacks payments capability',
      agentId: agent.agentId,
    });
  }

  // Process payment...
  res.json({ status: 'ok' });
});

app.listen(3000, () => console.log('DCP-protected API on :3000'));

Configuration Options

import { dcpVerify } from '@dcp-ai/express';

app.use(dcpVerify({
  // Require a DCP bundle (403 if missing). Default: true
  requireBundle: true,

  // Header name for the bundle. Default: 'x-dcp-bundle'
  headerName: 'x-dcp-bundle',

  // Check agent revocation status against a service. Default: false
  checkRevocation: true,
  revocationServiceUrl: 'http://localhost:3003',

  // Cache verification results (seconds). Default: 0 (no cache)
  cacheTtlSeconds: 60,

  // V2: Require hybrid composite signatures
  requireHybrid: true,

  // V2: Fine-grained verifier policy
  verifierPolicy: {
    default_mode: 'hybrid_required',
    require_session_binding: true,
    require_composite_binding: true,
  },

  // Custom failure handler
  onFailure: (req, res, errors) => {
    res.status(403).json({ verified: false, errors, hint: 'Include X-DCP-Bundle header' });
  },
}));

Sending DCP Bundles from a Client

import { generateKeypair, BundleBuilder, signBundle } from '@dcp-ai/sdk';

// Build and sign a bundle (see QUICKSTART.md for full example)
const signed = signBundle(bundle, keys.secretKeyB64);

// Send via header
const response = await fetch('http://localhost:3000/api/data', {
  headers: {
    'X-DCP-Bundle': JSON.stringify(signed),
    'Content-Type': 'application/json',
  },
});

// Or send via body
const response2 = await fetch('http://localhost:3000/api/data', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    signed_bundle: signed,
    // ... other body fields
  }),
});

V2 Bundle Verification

The middleware auto-detects V1 and V2 bundles. For V2 bundles, it additionally verifies:

  • Composite signatures — Ed25519 + ML-DSA-65 hybrid validation
  • Manifest integrity — All artifact hashes match
  • Session binding — Session nonce consistency across all artifacts
  • PQ checkpoint integrity (when present)
// V2-specific agent properties
app.get('/api/secure', (req: express.Request & { dcpAgent?: DCPAgent }, res) => {
  const agent = req.dcpAgent!;

  if (agent.dcpVersion === '2.0') {
    console.log('Key IDs:', agent.kids);
    console.log('Session:', agent.sessionNonce);
  }

  res.json({ verified: true, version: agent.dcpVersion });
});

DCPAgent Interface

The verified agent identity attached to req.dcpAgent:

interface DCPAgent {
  agentId: string;        // Unique agent identifier
  humanId: string;        // Bound human principal
  publicKey: string;      // Primary public key (base64)
  capabilities: string[]; // ['browse', 'api_call', 'payments', ...]
  riskTier: string;       // 'low' | 'medium' | 'high'
  status: string;         // 'active' | 'revoked' | 'suspended'
  dcpVersion: '1.0' | '2.0';

  // V2-only fields
  kids?: string[];        // Key identifiers for all keys
  sessionNonce?: string;  // Session nonce from bundle manifest
}

Next Steps