@easylegal/node
v0.1.0
Published
EasyLegal server SDK — session token minting and webhook signature verification. The only place your secret key belongs.
Readme
@easylegal/node
Server SDK for EasyLegal — embeddable contract infrastructure. This package is the only place your EasyLegal secret key belongs: it mints the short-lived session tokens your frontend uses, and verifies signatures on webhooks and data-connector requests.
npm install @easylegal/nodeMint session tokens (required)
Your server exchanges its secret key for a 15-minute, workspace-scoped JWT. Hand only the token to the browser; re-mint freely on expiry.
import { EasyLegal, EasyLegalError } from "@easylegal/node";
const easylegal = new EasyLegal({ secretKey: process.env.EASYLEGAL_SECRET_KEY });
// e.g. a Next.js route handler at /api/easylegal/session
export async function POST() {
try {
const session = await easylegal.sessions.create({
// Your own stable id + display name for this business/workspace.
workspace: { externalRef: firm.id, name: firm.name },
user: { id: currentUser.id, role: "owner" }, // optional attribution
});
return Response.json(session); // { token, expiresAt }
} catch (err) {
if (err instanceof EasyLegalError) {
// 402 + reason "account_lapsed" → render your locked/paywall state.
return Response.json({ error: err.message, reason: err.reason }, { status: err.status });
}
throw err;
}
}Workspaces are upserted by externalRef — no separate provisioning call.
Verify webhooks
EasyLegal signs outbound webhooks HMAC-SHA256 over ${timestamp}.${body}
(easylegal-signature: t=<unix>,v1=<hex>), with a freshness tolerance so
captured requests can't be replayed.
const ok = easylegal.webhooks.verify(rawBody, req.headers["easylegal-signature"], signingSecret);Data connector (bulk & background sends)
When a send references one of your records by id instead of inlining the payload, EasyLegal fetches it from the connector URL you registered in the dashboard. Verify the signature over the raw body, scope the lookup, and return the same payload shape you registered:
export async function POST(req: Request) {
const raw = await req.text();
if (!easylegal.connector.verify(raw, req.headers.get("x-easylegal-signature") ?? "", signingSecret))
return Response.json({ error: "bad signature" }, { status: 401 });
const { subjectRef, workspaceExternalRef } = JSON.parse(raw);
const record = await findRecord(workspaceExternalRef, subjectRef);
if (!record) return Response.json({ error: "unknown subject" }, { status: 404 });
return Response.json(record.payload);
}Your signing secret lives in the EasyLegal dashboard (Payload schema → Data connector). Zero dependencies; Node 18+.
