Node SDK · Minter

Use the minter when your application's frontend wants to display events directly — see Embed Tokens for the full model. Construct once at boot, mint per request:

import * as minter from "@everscribe/sdk-node/minter";

const m = new minter.Client(projectId, apiKey);

The token returned from mintToken is a JWT. Hand it to your frontend via your normal page-render path. Never expose your project API key to the browser.

Single-tenant

Use when your project has one customer per project, or when you're embedding the UI in your own internal tooling. The token has no tenant_id claim, so the embed shows every event in the project.

app.get("/api/embed-token", async (req, res) => {
    const user = await authenticate(req);
    if (!user) {
        res.status(401).send("unauthorized");
        return;
    }

    try {
        const token = await m.mintToken({
            // No tenantId — the project has one customer (or is
            // internal), so the token doesn't need to filter by tenant.
            expiresIn: 60 * 60 * 1000, // 1 hour, in ms
            allowedColumns: ["occurred_at", "action", "actor", "target"],
        });
        res.json({ token });
    } catch {
        res.status(500).send("mint failed");
    }
});

Multi-tenant

Use when your project partitions events by tenant_id and each customer should only see their own. Mint a token whose tenantId matches the signed-in user's tenant — the server enforces the scope on every read.

app.get("/api/embed-token", async (req, res) => {
    const user = await authenticate(req);
    if (!user) {
        res.status(401).send("unauthorized");
        return;
    }

    try {
        const token = await m.mintToken({
            // tenantId set to the signed-in user's tenant — reads
            // filtered server-side. For an admin view (your internal
            // support tool that should see every tenant), use the
            // same minter but omit tenantId.
            tenantId: user.tenantId,
            expiresIn: 60 * 60 * 1000,
            allowedColumns: ["occurred_at", "action", "actor", "target"],
            allowedActions: ["user.*", "billing.invoice.created"],
        });
        res.json({ token });
    } catch {
        res.status(500).send("mint failed");
    }
});

Multi-tenant products often expose two endpoints:

Endpoint Token Used for
/api/embed-token/customer tenantId = signed-in user's tenant the end-customer's view of their own audit trail
/api/embed-token/admin tenantId omitted internal admin / support tool, shows every tenant

Same minter, different scoping rules.

TokenOptions

Field Type Notes
tenantId string Optional. Scopes reads to events with matching tenant_id. Trimmed; ≤ 256 chars. Omit for unscoped (single-tenant or admin view).
expiresIn number Token lifetime in milliseconds. Server clamps to [60_000, 86_400_000]. Omit or pass 0 for the server default (1h).
allowedColumns string[] Optional whitelist of Event JSON field names (snake_case). Empty array rejected.
allowedActions string[] Exact match or suffix wildcard (user.*). Empty array rejected.

The SDK exports MIN_EXPIRES_IN_MS, MAX_EXPIRES_IN_MS, and ALLOWED_COLUMNS constants if you want to validate before calling.