Express routes
The server half for Express apps: a mountable router that proxies component requests to the Handset API. Your key stays server-side; your session decides tenant access.
Installation
npx shadcn@latest add @handset/express-routesLands at server/handset-routes.ts and expects HANDSET_API_KEY in your environment. Works with Express 4 and 5 on Node 18+.
Mounting
Mount at /api/handset — the base path the components use by default:
import express from "express";
import { handsetRoutes } from "./handset-routes";
const app = express();
app.use("/api/handset", handsetRoutes());Serving your React app from a different origin? Point the components at your API host with <HandsetProvider baseUrl="https://api.yourapp.com/api/handset"> and handle CORS as you do for the rest of your API.
The auth boundary
One function is yours to implement. Everything the components can see flows through it:
async function resolveTenantId(req: Request): Promise<string | null> {
if (!req.session?.user) throw { status: 401, message: "Sign in first" };
return req.session.user.handsetTenantId; // "tnt_…"
}The resolved tenant is injected into every read — anything the browser claims is ignored. Return null for single-tenant accounts.
The allowlist
Identical to the Next.js proxy: only the endpoints the components need are forwarded, everything else 404s. Buying numbers, porting, compliance — none of that is reachable from the browser. Extend the list deliberately if you build more.
Environment
HANDSET_API_KEY=sk_test_… # required; sk_live_… in production
HANDSET_API_URL= # optional override, defaults to https://api.handset.dev/v1