@forwardpath/node
Server-side helpers for the ForwardPath intake API. Use it to sign users for
publishable-key sessions with createUserHash, or to mint short-lived intake
sessions with your secret API key, so the key never reaches the browser. It
ships a ready-made route handler for Next.js App Router (or any runtime with
web Request/Response).
Install
npm install @forwardpath/node
Verify users with createUserHash
With a publishable key, the browser mints its own sessions and names the
user. Without proof, ForwardPath marks that user claimed, i.e. unverified.
To mark them verified, sign the user on your server with the key's
identity secret (fpiv_…, shown once when you create the key) and pass the
hash to the browser.
import { createUserHash } from "@forwardpath/node";
const userHash = createUserHash({
identitySecret: process.env.FORWARDPATH_IDENTITY_SECRET!,
user: { id: user.id, email: user.email },
});
// Render it into the page:
// <ForwardPathProvider publishableKey="fppk_…" user={user} userHash={userHash}>
The hash is lowercase hex HMAC-SHA256 of JSON.stringify([id, email]), with
the id trimmed and the email trimmed and lowercased (null when absent). It
signs the id and email, not the name. The browser must send the same id and
email, or the session fails with a 401. createUserHash throws in a browser
or if the secret doesn't start with fpiv_. Keep the secret in a
server-only env var.
Keep your API key on the server
Your API key (fp_<keyId>.<secret>) can mint sessions for any user. Store it
in a server-only env var. createForwardPathClient throws if it runs in a
browser or if the key is malformed. The route handler responds with only the
session token and its expiry, never the key.
Next.js route
// app/api/forwardpath/session/route.ts
import {
createForwardPathClient,
createIntakeSessionHandler,
} from "@forwardpath/node";
import { auth } from "@/auth"; // your own auth
const client = createForwardPathClient({
apiKey: process.env.FORWARDPATH_API_KEY!,
baseUrl: "https://app.forwardpath.ai",
});
export const POST = createIntakeSessionHandler({
client,
projectSlug: "acme-app",
getUser: async () => {
const session = await auth();
if (!session?.user) return null; // responds 401
return {
externalId: session.user.id,
email: session.user.email,
name: session.user.name ?? undefined,
};
},
});
The browser calls it with POST /api/forwardpath/session and gets back
{ token, expiresAt }. Pass the token to @forwardpath/js or
@forwardpath/react. The body may carry { clientContext } (e.g. from
collectClientContext()); the handler forwards it to ForwardPath.
Handler responses:
| Status | When |
|---|---|
| 200 | { token, expiresAt } |
| 400 | Body isn't a JSON object, or ForwardPath rejected the payload |
| 401 | getUser returned null |
| 502 | ForwardPath failed for another reason (e.g. bad API key) |
Minting a session yourself
const session = await client.createIntakeSession({
projectSlug: "acme-app",
user: { externalId: "u_123", email: "[email protected]", name: "Ada" },
clientContext: { appName: "Acme", appVersion: "2.4.0" }, // optional
metadata: { plan: "pro" }, // optional, stored on the reporter
});
// { token, expiresAt, projectSlug, reporter }
A non-2xx response rejects with ForwardPathApiError (re-exported from
@forwardpath/js), which has status, code and title.