# Express.js middleware

Middleware that accepts either `x-agent-wallet` (Path 1) or `Authorization: Bearer <token>` (Path 2). ProofPack supports both JWS and JWT; standard Bearer token handling applies.

**Implementation note:** The wallet-only path uses ProofPack’s `IsDelegateAttestationVerifier` from `@zipwire/proofpack-ethereum`; the full-proof path uses `AttestedMerkleExchangeReader` and a verification context from `@zipwire/proofpack`. For the exact verifier config and context setup, see the [Path 1 example](https://docs.zipwire.io/tools-and-integrations/proofpack-agent-delegation/path1-wallet-only-javascript) and the [ProofPack repo](https://github.com/zipwireapp/ProofPack).

```javascript
import express from 'express';
import { IsDelegateAttestationVerifier } from '@zipwire/proofpack-ethereum';
import { AttestedMerkleExchangeReader } from '@zipwire/proofpack';

const app = express();

// Verifier: use full config (delegationSchemaUid, acceptedRoots, etc.) — see Path 1 and ProofPack repo
const verifier = new IsDelegateAttestationVerifier({ chains: ['base-sepolia', 'base'] }, config);
const reader = new AttestedMerkleExchangeReader();

// Middleware: Verify agent authorization
app.use(async (req, res, next) => {
  const agentWallet = req.headers['x-agent-wallet'];
  const authHeader = req.headers['authorization'];

  if (!agentWallet && !authHeader) {
    return res.status(400).json({ error: 'Agent wallet or JWS/JWT required' });
  }

  try {
    if (authHeader?.startsWith('Bearer ')) {
      // Full proof path
      const token = authHeader.slice(7);
      const result = await reader.readAsync(token, verificationContext);

      if (!result.isValid) {
        return res.status(403).json({ error: 'Invalid authorization proof' });
      }

      req.agent = {
        wallet: result.agentWallet,
        claims: result.document.merkleTree.leaves,
        verified: true
      };
    } else if (agentWallet) {
      // Wallet-only check (returns AttestationResult with .isValid)
      const result = await verifier.verifyByWallet(agentWallet);

      if (!result.isValid) {
        return res.status(403).json({ error: 'Agent not authorized by human' });
      }

      req.agent = {
        wallet: agentWallet,
        verified: true
      };
    }

    next();
  } catch (err) {
    res.status(500).json({ error: 'Verification failed', details: err.message });
  }
});

// Your API endpoints now have req.agent with verified authorization
app.post('/api/time-tracking/log', (req, res) => {
  console.log(`Agent ${req.agent.wallet} logging time`);
  // Process request
});

app.get('/api/payments/status', (req, res) => {
  if (!req.agent.claims?.verifiedHuman) {
    return res.status(403).json({ error: 'Payment queries require human verification' });
  }
  // Return payment status
});
```

Configure `config` (verifier) and `verificationContext` (reader) per the [ProofPack repo](https://github.com/zipwireapp/ProofPack) and [Path 1](https://docs.zipwire.io/tools-and-integrations/proofpack-agent-delegation/path1-wallet-only-javascript) / [Quick setup](https://docs.zipwire.io/tools-and-integrations/proofpack-agent-delegation/quick-setup-verification-context). Full guide: [ProofPack & Agent Delegation](https://docs.zipwire.io/tools-and-integrations/proofpack-agent-delegation).
