The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.

Viewing files at commit 5239911501a5Commit detailsView latest

api/index.ts 61 lines · 2.8 KB · typescript
1
import type { IncomingMessage, ServerResponse } from 'node:http';
2
import { buildApi } from '../apps/api/src/app.js';
3
import { TrustEngine } from '../packages/core/src/index.js';
4
import { HostedRepository } from '../packages/persistence/src/hosted.js';
5
import { dashboardTokenFromCookie, loadAuth0Profile, verifyAuth0Token } from './auth0.js';
6
7
const databaseUrl = process.env.DATABASE_URL;
8
const repository = databaseUrl ? new HostedRepository(databaseUrl) : undefined;
9
const app = buildApi(new TrustEngine(), undefined, repository);
10
const ready = app.ready();
11
12
export default async function handler(request: IncomingMessage, response: ServerResponse) {
13
  const incoming = new URL(request.url ?? '/', 'https://openclasp.local');
14
  const target = incoming.searchParams.get('path');
15
  if (target) request.url = target;
16
  if ((request.url ?? '').startsWith('/v0.1/')) {
17
    const authorization = request.headers.authorization;
18
    const token = authorization?.startsWith('Bearer ')
19
      ? authorization.slice(7)
20
      : dashboardTokenFromCookie(request.headers.cookie);
21
    if (!token) {
22
      response.statusCode = 401;
23
      response.setHeader('content-type', 'application/json');
24
      response.end(JSON.stringify({ error: 'authentication_required' }));
25
      return;
26
    }
27
    try {
28
      const runtimeSelfService = /^\/v0\.1\/runtime(?:\/bootstrap|\/heartbeat)?(?:\?|$)/.test(
29
        request.url ?? '',
30
      );
31
      if (token.startsWith('oc_at_') && runtimeSelfService) {
32
        if (!repository) throw new Error('Agent access tokens are not configured');
33
        const authentication = await repository.verifyAgentAccessToken(token);
34
        // Existing beta tokens had only mcp:access. They remain accepted because
35
        // they are already cryptographically bound to the same agent.
36
        if (
37
          !authentication.scopes.includes('runtime:connect') &&
38
          !authentication.scopes.includes('mcp:access')
39
        )
40
          throw new Error('Agent token cannot connect a runtime');
41
        request.headers['x-openclasp-operator'] = authentication.operatorId;
42
        request.headers['x-openclasp-bound-agent'] = authentication.agentId;
43
      } else {
44
        const authentication = await verifyAuth0Token(token, { dashboard: true });
45
        request.headers['x-openclasp-operator'] = authentication.payload.sub!;
46
        if ((request.url ?? '').startsWith('/v0.1/account')) {
47
          const user = await loadAuth0Profile(token);
48
          request.headers['x-openclasp-email'] = encodeURIComponent(user.email ?? '');
49
          request.headers['x-openclasp-name'] = encodeURIComponent(user.name ?? '');
50
        }
51
      }
52
    } catch {
53
      response.statusCode = 401;
54
      response.setHeader('content-type', 'application/json');
55
      response.end(JSON.stringify({ error: 'invalid_session' }));
56
      return;
57
    }
58
  }
59
  await ready;
60
  app.server.emit('request', request, response);
61
}