auth.ts
1 import { validateAccessKey } from '@/lib/server/storage-auth' 2 3 export interface A2AAuthResult { 4 valid: boolean 5 agentId: string | null 6 error?: string 7 } 8 9 /** 10 * Validate an inbound A2A request using the SwarmClaw access key. 11 * Checks `Authorization: Bearer <key>` or `x-a2a-access-key` header. 12 */ 13 export function validateA2ARequest(req: Request): A2AAuthResult { 14 const authHeader = req.headers.get('authorization') 15 const a2aKeyHeader = req.headers.get('x-a2a-access-key') 16 17 let key: string | null = null 18 if (authHeader?.startsWith('Bearer ')) { 19 key = authHeader.slice(7) 20 } else if (a2aKeyHeader) { 21 key = a2aKeyHeader 22 } 23 24 if (!key) { 25 return { valid: false, agentId: null, error: 'Missing authentication — provide Authorization: Bearer <key> or x-a2a-access-key header' } 26 } 27 28 if (!validateAccessKey(key)) { 29 return { valid: false, agentId: null, error: 'Invalid access key' } 30 } 31 32 const agentId = req.headers.get('x-a2a-agent-id') 33 return { valid: true, agentId } 34 } 35 36 /** 37 * Extract A2A-specific headers from an inbound request. 38 */ 39 export function extractA2AHeaders(req: Request): { targetAgentId: string | null; requesterAgentId: string | null } { 40 return { 41 targetAgentId: req.headers.get('x-a2a-target-agent-id'), 42 requesterAgentId: req.headers.get('x-a2a-agent-id'), 43 } 44 } 45 46 /** 47 * Build auth headers for outbound A2A requests to remote agents. 48 */ 49 export function buildA2AAuthHeaders(accessKey: string): Record<string, string> { 50 return { 51 'Content-Type': 'application/json', 52 'Authorization': `Bearer ${accessKey}`, 53 } 54 }