UNPKG

@vigilbase/cli

Version:

Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.

22 lines (21 loc) • 1.64 kB
import { z } from 'zod'; /** Validate grant binding from the trusted issuer's TLS response. One verifies signatures at its API boundary. */ export function readIdentityTokenMetadata(token, binding) { try { const parts = token.split('.'); if (parts.length !== 3 || !parts[2]) throw new Error(); z.object({ alg: z.literal('EdDSA'), typ: z.literal('at+jwt') }).parse(JSON.parse(Buffer.from(parts[0], 'base64url').toString('utf8'))); const claims = z.object({ iss: z.literal(binding.issuer), sub: z.string().min(1), aud: z.union([z.literal(binding.resource), z.array(z.string()).min(1).max(2)]), azp: z.literal(binding.clientId), iat: z.number().finite(), exp: z.number().finite(), 'https://vigilbase.com/org_id': z.string().min(1) }).parse(JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'))); const audiences = typeof claims.aud === 'string' ? [claims.aud] : claims.aud; if (!audiences.includes(binding.resource) || new Set(audiences).size !== audiences.length || audiences.some(aud => aud !== binding.resource && aud !== `${binding.issuer}/api/auth/oauth2/userinfo`)) throw new Error(); const now = Date.now() / 1000; if (claims.exp <= now - 30 || claims.iat > now + 30 || claims.exp <= claims.iat || claims.exp - claims.iat > 300) throw new Error(); return { organizationId: claims['https://vigilbase.com/org_id'], subject: claims.sub }; } catch { throw new Error('Identity token does not match the expected issuer, client, organization, five-minute lifetime, and exact One audience.'); } }