Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Native library reference. Extended CLI examples use jacs-compat. This source reference can include unreleased changes; see the package guide for installation and MCP profiles for available tools.

HTTP Signing and Verification

Source and published packages: Version 0.16.1 has a recorded release inventory. Version 0.16.0 is the first release whose source includes the native PQ DID/JWK and Agent Card behavior. See the identity integration guide.

HTTP integration has two separate jobs: verifying signed documents and binding authorization to the actual request. The maintained Express and Koa adapters verify document bodies and optionally sign responses. They do not implement request-bound authorization. The old @hai.ai/jacs/http adapter calls removed root-module helpers; migrate to those framework adapters instead.

Request-bound credentials

Use the synchronous JacsSimpleAgent instance API. Run this client as an ES module (.mjs), with an existing client configuration and a trusted server-key map provisioned independently of the response:

import { readFile } from 'node:fs/promises';
import { JacsSimpleAgent } from '@hai.ai/jacs';

const agent = JacsSimpleAgent.load('./client/jacs.config.json');
const serverKeysJson = await readFile('./trusted-server-keys.json', 'utf8');
const url = 'https://api.example.com/v1/jobs?mode=strict';
const body = JSON.stringify({ action: 'inspect', jobId: '42' });
const authorization = agent.buildRequestAuthHeader('POST', url, body, 'jobs-api');

const response = await fetch(url, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', Authorization: authorization },
  body,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const event = JSON.parse(agent.unwrapSignedEvent(await response.text(), serverKeysJson));
console.log(event.data);

The key map is a JSON object mapping expected server agent IDs to trusted PEM public keys. Do not construct it from an unverified response. The credential binds method, absolute URL including query, exact body bytes, audience, signer/key, issue time, and nonce. Send the final body unchanged.

The server must verify the same request context with a trusted key, enforce its caller policy, and atomically consume the nonce before executing work. Neither a generic signed body nor the legacy buildAuthHeader() provides that binding. See request-bound HTTP authorization for the server contract.

Signed response events

A server with an initialized JacsSimpleAgent creates the v2 envelope with:

const envelope = agent.signResponse(JSON.stringify({ result: 42 }));

unwrapSignedEvent(envelope, serverKeysJson) verifies the complete envelope, including payload and metadata. It throws on unsigned input, legacy payload-only envelopes, unknown signers, and mutations. Its result contains verified, data, signerId, timestamp, algorithm, and documentId. Verification alone does not consume an event for replay prevention or bind it to an outstanding request; enforce those application constraints before use.

A signature proves possession of the selected key and integrity of the signed scope. Real-world identity, authorization, freshness, and permitted use come from the verifier's trust and application policies. Signatures do not encrypt the payload; use HTTPS for transport confidentiality.

Signed document bodies

For document exchange, use JacsClient.signMessage() and verify() or the framework adapters. Configure sender trust and route authorization separately. Express's authReplay and Koa's matching option add freshness and in-process deduplication for signed bodies; they do not bind method, URL, or audience.