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

Viewing files at commit 03be656e7804Commit detailsView latest

packages/persistence/src/access-token.ts 40 lines · 1.3 KB · typescript
1
import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
2
3
const TOKEN_PREFIX = 'oc_at_';
4
const TOKEN_PATTERN = /^oc_at_([A-Za-z0-9_-]{16})\.([A-Za-z0-9_-]{43})$/;
5
6
export type AgentAccessTokenMetadata = {
7
  tokenId: string;
8
  agentId: string;
9
  name: string;
10
  scopes: string[];
11
  createdAt: string;
12
  expiresAt: string;
13
  lastUsedAt?: string;
14
  revokedAt?: string;
15
};
16
17
export function hashAgentAccessToken(token: string): string {
18
  return createHash('sha256').update(token).digest('hex');
19
}
20
21
export function createAgentAccessToken() {
22
  const tokenId = randomBytes(12).toString('base64url');
23
  const secret = randomBytes(32).toString('base64url');
24
  const token = `${TOKEN_PREFIX}${tokenId}.${secret}`;
25
  return { tokenId, token, tokenHash: hashAgentAccessToken(token) };
26
}
27
28
export function agentAccessTokenId(token: string): string | undefined {
29
  return TOKEN_PATTERN.exec(token)?.[1];
30
}
31
32
export function agentAccessTokenClientId(tokenId: string): string {
33
  return `openclasp-agent-token:${tokenId}`;
34
}
35
36
export function matchesAgentAccessToken(token: string, expectedHash: string): boolean {
37
  const actual = Buffer.from(hashAgentAccessToken(token), 'hex');
38
  const expected = Buffer.from(expectedHash, 'hex');
39
  return actual.length === expected.length && timingSafeEqual(actual, expected);
40
}