Setting up with AI? Use this single prompt:
Choose your tech stack
Choose all that apply.
Select a tool to show setup instructions.
- Unified AI Prompt
- Next.js
- React
- JS/TS
- Tanstack Start
- Node.js
- Bun
- Python
- Other (REST API)
- Convex
- Supabase
- CLI
Next.js SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for Next.js .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/next npm package with your preferred package manager:npm i @hexclave/next
# or: pnpm i @hexclave/next
# or: yarn add @hexclave/next
# or: bun add @hexclave/next
Initializing the Hexclave App
HexclaveClientApp constructor:import { HexclaveClientApp } from "@hexclave/next";
export const hexclaveClientApp = new HexclaveClientApp({
tokenStore: "cookie", // "nextjs-cookie" for Next.js, "cookie" for other web frontends, null for backend environments
urls: {
default: {
type: "hosted",
}
},
});
The SDK auto-captures page-view and click analytics. To turn this off (and silence theIn a backend where you can keep a secret key safe, you can use theANALYTICS_NOT_ENABLEDconsole warning that appears until you enable the Analytics app in your dashboard), passanalytics: { enabled: false }.
HexclaveServerApp, which provides access to more sensitive APIs compared to HexclaveClientApp:import { HexclaveServerApp } from "@hexclave/next";
import { hexclaveClientApp } from "./client";
export const hexclaveServerApp = new HexclaveServerApp({
inheritsFrom: hexclaveClientApp,
});
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/next/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/next/config path (never from @hexclave/next directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Creating a <HexclaveProvider /> and <HexclaveTheme />
HexclaveProvider and HexclaveTheme components that should wrap your entire app at the root level.You can do this in the layout.tsx file in the app directory. The root layout must render the <html> and <body> tags, and HexclaveProvider/HexclaveTheme must go inside:import { HexclaveProvider, HexclaveTheme } from "@hexclave/next";
import { hexclaveServerApp } from "@/hexclave/server";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<HexclaveProvider app={hexclaveServerApp}>
<HexclaveTheme>
{children}
</HexclaveTheme>
</HexclaveProvider>
</body>
</html>
);
}
Add Suspense boundary
useXyz React hooks for getXyz/listXyz functions. For example, useUser is like getUser, but as a suspending React hook.To support the suspension, you need to add a suspense boundary around your app.In Next.js, this can be easily done by adding a loading.tsx file in the app directory:export default function Loading() {
return <div>Loading...</div>;
}
React SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for React .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/react npm package with your preferred package manager:npm i @hexclave/react
# or: pnpm i @hexclave/react
# or: yarn add @hexclave/react
# or: bun add @hexclave/react
Initializing the Hexclave App
HexclaveClientApp constructor:import { HexclaveClientApp } from "@hexclave/react";
export const hexclaveClientApp = new HexclaveClientApp({
tokenStore: "cookie", // "nextjs-cookie" for Next.js, "cookie" for other web frontends, null for backend environments
urls: {
default: {
type: "hosted",
}
},
});
The SDK auto-captures page-view and click analytics. To turn this off (and silence theANALYTICS_NOT_ENABLEDconsole warning that appears until you enable the Analytics app in your dashboard), passanalytics: { enabled: false }.
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/react/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/react/config path (never from @hexclave/react directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Creating a <HexclaveProvider /> and <HexclaveTheme />
HexclaveProvider and HexclaveTheme components that should wrap your entire app at the root level.For example, if you have an App.tsx file, update it as follows:import { HexclaveProvider, HexclaveTheme } from "@hexclave/react";
import { hexclaveClientApp } from "./hexclave/client";
export default function App() {
return (
<HexclaveProvider app={hexclaveClientApp}>
<HexclaveTheme>
{/* your app content */}
</HexclaveTheme>
</HexclaveProvider>
);
}
Add Suspense boundary
useXyz React hooks for getXyz/listXyz functions. For example, useUser is like getUser, but as a suspending React hook.To support the suspension, you need to add a suspense boundary around your app.The easiest way to do this is to just wrap your entire app in a Suspense component:import { Suspense } from "react";
import { HexclaveProvider, HexclaveTheme } from "@hexclave/react";
import { hexclaveClientApp } from "./hexclave/client";
export default function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HexclaveProvider app={hexclaveClientApp}>
<HexclaveTheme>
{/* your app content */}
</HexclaveTheme>
</HexclaveProvider>
</Suspense>
);
}
Other JS/TS SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for Other JS/TS .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/js npm package with your preferred package manager:npm i @hexclave/js
# or: pnpm i @hexclave/js
# or: yarn add @hexclave/js
# or: bun add @hexclave/js
Initializing the Hexclave App
HexclaveClientApp constructor:import { HexclaveClientApp } from "@hexclave/js";
export const hexclaveClientApp = new HexclaveClientApp({
tokenStore: "cookie", // "nextjs-cookie" for Next.js, "cookie" for other web frontends, null for backend environments
urls: {
default: {
type: "hosted",
}
},
});
The SDK auto-captures page-view and click analytics. To turn this off (and silence theIn a backend where you can keep a secret key safe, you can use theANALYTICS_NOT_ENABLEDconsole warning that appears until you enable the Analytics app in your dashboard), passanalytics: { enabled: false }.
HexclaveServerApp, which provides access to more sensitive APIs compared to HexclaveClientApp:import { HexclaveServerApp } from "@hexclave/js";
export const hexclaveServerApp = new HexclaveServerApp({
tokenStore: null,
urls: {
default: {
type: "hosted",
}
},
});
HexclaveServerApp from a HexclaveClientApp object:import { HexclaveServerApp } from "@hexclave/js";
import { hexclaveClientApp } from "./client";
export const hexclaveServerApp = new HexclaveServerApp({
inheritsFrom: hexclaveClientApp,
});
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/js/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/js/config path (never from @hexclave/js directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Backend: Update callers with header & get user
hexclaveClientApp.getAuthorizationHeader() as the Authorization header into your backend endpoints when the user is signed in:// NOTE: This is your frontend's code
const authorizationHeader = await hexclaveClientApp.getAuthorizationHeader();
const response = await fetch("/my-backend-endpoint", {
headers: {
...(authorizationHeader ? { Authorization: authorizationHeader } : {}),
},
});
// ...
tokenStore of the functions that access the user object:// NOTE: This is your backend's code
const user = await hexclaveServerApp.getUser({ tokenStore: request });
return new Response("Hello, " + user.displayName, { headers: { "Cache-Control": "private, no-store" } });
request is an object that follows the shape { headers: Record<string, string | null> | { get: (name: string) => string | null } }.
Make sure that HTTP caching is disabled with Cache-Control: private, no-store for authenticated backend endpoints.
If you cannot use getAuthorizationHeader(), for example because you are using a protocol other than HTTP, you can use getAuthJson() instead:// Frontend:
await rpcCall("my-rpc-endpoint", {
data: {
auth: await hexclaveClientApp.getAuthJson(),
},
});
// Backend:
const user = await hexclaveServerApp.getUser({ tokenStore: data.auth });
return new RpcResponse("Hello, " + user.displayName);
Tanstack Start SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for Tanstack Start .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/tanstack-start npm package with your preferred package manager:npm i @hexclave/tanstack-start
# or: pnpm i @hexclave/tanstack-start
# or: yarn add @hexclave/tanstack-start
# or: bun add @hexclave/tanstack-start
Initializing the Hexclave App
HexclaveClientApp constructor:import { HexclaveClientApp } from "@hexclave/tanstack-start";
export const hexclaveClientApp = new HexclaveClientApp({
tokenStore: "cookie", // "nextjs-cookie" for Next.js, "cookie" for other web frontends, null for backend environments
urls: {
default: {
type: "hosted",
}
},
});
The SDK auto-captures page-view and click analytics. To turn this off (and silence theANALYTICS_NOT_ENABLEDconsole warning that appears until you enable the Analytics app in your dashboard), passanalytics: { enabled: false }.
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/tanstack-start/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/tanstack-start/config path (never from @hexclave/tanstack-start directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Creating a <HexclaveProvider /> and <HexclaveTheme />
HexclaveProvider and HexclaveTheme components that should wrap your entire app at the root level.TanStack Start uses file-based routes. The provider goes inside the root route’s component (the inner React tree), while the document shell stays in shellComponent. Update src/routes/__root.tsx:import { HexclaveProvider, HexclaveTheme } from "@hexclave/tanstack-start";
import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
import type { ReactNode } from "react";
import { hexclaveClientApp } from "../hexclave/client";
export const Route = createRootRoute({
shellComponent: RootDocument,
component: RootComponent,
});
function RootDocument({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
}
function RootComponent() {
return (
<HexclaveProvider app={hexclaveClientApp}>
<HexclaveTheme>
<Outlet />
</HexclaveTheme>
</HexclaveProvider>
);
}
src/routeTree.gen.ts — it is regenerated automatically by the TanStack Start router from the files under src/routes/.Add Suspense boundary
useXyz React hooks for getXyz/listXyz functions. For example, useUser is like getUser, but as a suspending React hook.To support the suspension, you need to add a suspense boundary around your app.wrap the <Outlet /> in your root route with a Suspense boundary so the document shell can stream while child routes wait on Hexclave. Update RootComponent in src/routes/__root.tsx:import { Suspense } from "react";
// ...other imports...
function RootComponent() {
return (
<HexclaveProvider app={hexclaveClientApp}>
<HexclaveTheme>
<Suspense fallback={<div>Loading...</div>}>
<Outlet />
</Suspense>
</HexclaveTheme>
</HexclaveProvider>
);
}
Add the Hexclave handler route
HexclaveHandler component mounted at /handler/*. In TanStack Start, expose it as a splat file route at src/routes/handler/$.tsx:import { HexclaveHandler } from "@hexclave/tanstack-start";
import { createFileRoute, useLocation } from "@tanstack/react-router";
export const Route = createFileRoute("/handler/$")({
ssr: false,
component: HandlerPage,
});
function HandlerPage() {
const { pathname } = useLocation();
return <HexclaveHandler fullPage location={pathname} />;
}
- The route is opted out of SSR with
ssr: false. The handler runs browser-only auth flows (cookies, redirects, popups), so rendering it on the server provides no benefit and can fight with hydration. Other routes can opt into or out of SSR per-route the same way. - Hexclave resolves the current user during SSR by reading TanStack Start’s request cookies through
@hexclave/tanstack-start’s server context. No extra wiring is required —useUser()“just works” on both server and client routes as long astokenStore: "cookie"is set onHexclaveClientApp.
Node.js SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for Node.js .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/js npm package with your preferred package manager:npm i @hexclave/js
# or: pnpm i @hexclave/js
# or: yarn add @hexclave/js
# or: bun add @hexclave/js
Initializing the Hexclave App
HexclaveServerApp, which provides access to more sensitive APIs compared to HexclaveClientApp:import { HexclaveServerApp } from "@hexclave/js";
export const hexclaveServerApp = new HexclaveServerApp({
tokenStore: null,
urls: {
default: {
type: "hosted",
}
},
});
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/js/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/js/config path (never from @hexclave/js directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Update callers with header & get user
hexclaveClientApp.getAuthorizationHeader() as the Authorization header into your backend endpoints when the user is signed in:// NOTE: This is your frontend's code
const authorizationHeader = await hexclaveClientApp.getAuthorizationHeader();
const response = await fetch("/my-backend-endpoint", {
headers: {
...(authorizationHeader ? { Authorization: authorizationHeader } : {}),
},
});
// ...
tokenStore of the functions that access the user object:// NOTE: This is your backend's code
const user = await hexclaveServerApp.getUser({ tokenStore: request });
return new Response("Hello, " + user.displayName, { headers: { "Cache-Control": "private, no-store" } });
request is an object that follows the shape { headers: Record<string, string | null> | { get: (name: string) => string | null } }.
Make sure that HTTP caching is disabled with Cache-Control: private, no-store for authenticated backend endpoints.
If you cannot use getAuthorizationHeader(), for example because you are using a protocol other than HTTP, you can use getAuthJson() instead:// Frontend:
await rpcCall("my-rpc-endpoint", {
data: {
auth: await hexclaveClientApp.getAuthJson(),
},
});
// Backend:
const user = await hexclaveServerApp.getUser({ tokenStore: data.auth });
return new RpcResponse("Hello, " + user.displayName);
Bun SDK Setup Instructions
Follow these instructions in order to set up and get started with the Hexclave SDK for Bun .Note: These instructions are for setting up the Hexclave SDK to build your own CLIs. If you’re looking to use the Hexclave CLI instead, see the CLI documentation.Install dependencies
@hexclave/js npm package with your preferred package manager:npm i @hexclave/js
# or: pnpm i @hexclave/js
# or: yarn add @hexclave/js
# or: bun add @hexclave/js
Initializing the Hexclave App
HexclaveServerApp, which provides access to more sensitive APIs compared to HexclaveClientApp:import { HexclaveServerApp } from "@hexclave/js";
export const hexclaveServerApp = new HexclaveServerApp({
tokenStore: null,
urls: {
default: {
type: "hosted",
}
},
});
Setting up the project
Option 1: Running Hexclave's dashboard locally (recommended)
Option 1: Running Hexclave's dashboard locally (recommended)
hexclave.config.ts configuration file in the root directory of the workspace (or anywhere else):import type { HexclaveConfig } from "@hexclave/js/config";
// default: show-onboarding, which shows the onboarding flow for this project when Hexclave starts
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/js/config path (never from @hexclave/js directly, which would pull in the whole SDK and fail to load).To run your application with Hexclave, you can then start the dev environment and set environment variables expected by your application. Hexclave’s CLI has a dev command does both of these, so let’s install it as a dev dependency and wrap your existing dev script in your package.json:npm i -D @hexclave/cli
# or: pnpm i -D @hexclave/cli
# or: yarn add -D @hexclave/cli
# or: bun add --dev @hexclave/cli
{
// ...
"scripts": {
// ...
"dev": "hexclave dev --config-file ./hexclave.config.ts -- npm run dev:without-hexclave",
"dev:without-hexclave": "<your-existing-dev-script>"
}
}
hexclave dev injects all necessary environment variables into the app process automatically, so the app is ready to use without any extra environment variable setup.Option 2: Connecting to a production project hosted in the cloud
Option 2: Connecting to a production project hosted in the cloud
Frontend
Go to your project’s dashboard on app.hexclave.com and get the project ID. You can find it in the URL after the/projects/ part. Copy-paste it into your .env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
hexclave/client.ts file:export const hexclaveClientApp = new HexclaveClientApp({
// ...
projectId: "your-project-id",
});
Backend (or both frontend and backend)
First, navigate to the Project Keys page in the Hexclave dashboard and generate a new set of keys.Then, copy-paste them into your.env.local file (or wherever your environment variables are stored):HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
HexclaveServerApp constructor.Update callers with header & get user
hexclaveClientApp.getAuthorizationHeader() as the Authorization header into your backend endpoints when the user is signed in:// NOTE: This is your frontend's code
const authorizationHeader = await hexclaveClientApp.getAuthorizationHeader();
const response = await fetch("/my-backend-endpoint", {
headers: {
...(authorizationHeader ? { Authorization: authorizationHeader } : {}),
},
});
// ...
tokenStore of the functions that access the user object:// NOTE: This is your backend's code
const user = await hexclaveServerApp.getUser({ tokenStore: request });
return new Response("Hello, " + user.displayName, { headers: { "Cache-Control": "private, no-store" } });
request is an object that follows the shape { headers: Record<string, string | null> | { get: (name: string) => string | null } }.
Make sure that HTTP caching is disabled with Cache-Control: private, no-store for authenticated backend endpoints.
If you cannot use getAuthorizationHeader(), for example because you are using a protocol other than HTTP, you can use getAuthJson() instead:// Frontend:
await rpcCall("my-rpc-endpoint", {
data: {
auth: await hexclaveClientApp.getAuthJson(),
},
});
// Backend:
const user = await hexclaveServerApp.getUser({ tokenStore: data.auth });
return new RpcResponse("Hello, " + user.displayName);
Python Backend Setup
Follow these instructions to authenticate requests to a Python backend with Hexclave.This setup is for Python backends that do not use the JavaScript SDK. The backend flow is: your frontend sends the user’s access token to your backend, and your backend verifies it before serving protected data.Choose a project setup
Option 1: Local dashboard (recommended)
Option 1: Local dashboard (recommended)
hexclave.config.ts file for another frontend or backend, reuse that same file so the whole project shares one Hexclave config. Otherwise, create a new hexclave.config.ts file in your workspace:import type { HexclaveConfig } from "@hexclave/js/config";
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/js/config path (never from @hexclave/js directly, which would pull in the whole SDK and fail to load).Run your backend through the Hexclave CLI so it starts the local dashboard and injects the Hexclave environment variables:{
"scripts": {
"dev": "hexclave dev --config-file ./hexclave.config.ts -- <your-backend-dev-command>"
}
}
HEXCLAVE_PROJECT_ID and HEXCLAVE_SECRET_SERVER_KEY from the environment.Option 2: Hexclave Cloud project
Option 2: Hexclave Cloud project
HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
Install backend dependencies
requests for REST API verification. If you want to use JWT verification, also install PyJWT[crypto].pip install requests PyJWT[crypto]
Send the user's access token to your backend
// this is your frontend's code!
const { accessToken } = await user.getAuthJson();
const response = await fetch("<your-backend-endpoint>", {
headers: {
"x-stack-access-token": accessToken,
},
});
Verify the token
Verify with JWT
Verify with JWT
import os
import jwt
from jwt import PyJWKClient
from jwt.exceptions import InvalidTokenError
jwks_client = PyJWKClient(
f"https://api.hexclave.com/api/v1/projects/{os.environ['HEXCLAVE_PROJECT_ID']}/.well-known/jwks.json"
)
def get_current_user_id_from_jwt(request):
access_token = request.headers.get("x-stack-access-token")
if not access_token:
return None
try:
signing_key = jwks_client.get_signing_key_from_jwt(access_token)
payload = jwt.decode(
access_token,
signing_key.key,
algorithms=["ES256"],
audience=os.environ["HEXCLAVE_PROJECT_ID"],
)
return payload["sub"]
except InvalidTokenError:
return None
Verify with the Hexclave REST endpoint
Verify with the Hexclave REST endpoint
import os
import requests
def get_current_hexclave_user(request):
access_token = request.headers.get("x-stack-access-token")
if not access_token:
return None
response = requests.get(
"https://api.hexclave.com/api/v1/users/me",
headers={
"x-stack-access-type": "server",
"x-stack-project-id": os.environ["HEXCLAVE_PROJECT_ID"],
"x-stack-secret-server-key": os.environ["HEXCLAVE_SECRET_SERVER_KEY"],
"x-stack-access-token": access_token,
},
timeout=10,
)
if response.status_code == 200:
return response.json()
return None
200 OK, the user is authenticated. If the response is not 200 OK, treat the request as unauthenticated.Protect authenticated endpoints
x-stack-access-token, verifies it with either JWT verification or REST API verification, and returns 401 Unauthorized when verification fails.
Disable HTTP caching for authenticated responses with a header like Cache-Control: private, no-store.
Other Backend Setup (REST API)
Follow these instructions to authenticate requests from any backend language using Hexclave’s REST API.Use this option when your backend is not JavaScript/TypeScript or Python, or when you want to call Hexclave over plain HTTP. The backend flow is: your frontend sends the user’s access token to your backend, and your backend verifies it before serving protected data.Choose a project setup
Option 1: Local dashboard (recommended)
Option 1: Local dashboard (recommended)
hexclave.config.ts file for another frontend or backend, reuse that same file so the whole project shares one Hexclave config. Otherwise, create a new hexclave.config.ts file in your workspace:import type { HexclaveConfig } from "@hexclave/js/config";
export const config: HexclaveConfig = "show-onboarding";
/config entrypoint is lightweight and free of framework runtime code, so it can be safely loaded by tooling such as the local dashboard. If you later switch to a config object and want type-checking, wrap it with defineHexclaveConfig imported from the same @hexclave/js/config path (never from @hexclave/js directly, which would pull in the whole SDK and fail to load).Run your backend through the Hexclave CLI so it starts the local dashboard and injects the Hexclave environment variables:{
"scripts": {
"dev": "hexclave dev --config-file ./hexclave.config.ts -- <your-backend-dev-command>"
}
}
HEXCLAVE_PROJECT_ID and HEXCLAVE_SECRET_SERVER_KEY from the environment.Option 2: Hexclave Cloud project
Option 2: Hexclave Cloud project
HEXCLAVE_PROJECT_ID=<your-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
Send the user's access token to your backend
// this is your frontend's code!
const { accessToken } = await user.getAuthJson();
const response = await fetch("<your-backend-endpoint>", {
headers: {
"x-stack-access-token": accessToken,
},
});
Verify the token
Verify with JWT
Verify with JWT
1. Read the access token from the `x-stack-access-token` header.
2. Fetch the JWKS from:
https://api.hexclave.com/api/v1/projects/<your-project-id>/.well-known/jwks.json
3. Verify the JWT signature with an ES256-capable JWT library.
4. Verify the token audience is your Hexclave project ID.
5. Use the `sub` claim as the authenticated user ID.
6. Reject the request if any verification step fails.
Verify with the Hexclave REST endpoint
Verify with the Hexclave REST endpoint
curl https://api.hexclave.com/api/v1/users/me \
-H "x-stack-access-type: server" \
-H "x-stack-project-id: $HEXCLAVE_PROJECT_ID" \
-H "x-stack-secret-server-key: $HEXCLAVE_SECRET_SERVER_KEY" \
-H "x-stack-access-token: <access-token-from-request>"
200 OK, the user is authenticated. If the response is not 200 OK, treat the request as unauthenticated.Protect authenticated endpoints
x-stack-access-token, verifies it with either JWT verification or REST API verification, and returns 401 Unauthorized when verification fails.
Disable HTTP caching for authenticated responses with a header like Cache-Control: private, no-store.
Convex Setup
Follow these instructions to integrate Hexclave with Convex.Create or identify the Convex app
npm create convex@latest
npx convex dev
npm run dev
Install and configure Hexclave
npx @hexclave/cli@latest init
.env.local file.Also add the same Hexclave environment variables to the Convex deployment environment in the Convex dashboard.Configure Convex auth providers
convex/auth.config.ts:import { getConvexProvidersConfig } from "@hexclave/js";
// or: import { getConvexProvidersConfig } from "@hexclave/react";
// or: import { getConvexProvidersConfig } from "@hexclave/next";
export default {
providers: getConvexProvidersConfig({
projectId: process.env.HEXCLAVE_PROJECT_ID, // or process.env.NEXT_PUBLIC_HEXCLAVE_PROJECT_ID
}),
};
Connect Convex clients to Hexclave
convexClient.setAuth(hexclaveClientApp.getConvexClientAuth({}));
convexReactClient.setAuth(hexclaveClientApp.getConvexClientAuth({}));
convexHttpClient.setAuth(hexclaveClientApp.getConvexHttpClientAuth({ tokenStore: requestObject }));
Use Hexclave user data in Convex functions
import { query } from "./_generated/server";
import { hexclaveServerApp } from "../src/hexclave/server";
export const myQuery = query({
handler: async (ctx, args) => {
const user = await hexclaveServerApp.getPartialUser({ from: "convex", ctx });
return user;
},
});
Supabase Setup
This setup covers Supabase Row Level Security (RLS) with Hexclave JWTs. It does not sync user data between Supabase and Hexclave. Use Hexclave webhooks if you need data sync.
Create Supabase RLS policies
CREATE TABLE data (
id bigint PRIMARY KEY,
text text NOT NULL,
user_id UUID
);
INSERT INTO data (id, text, user_id) VALUES
(1, 'Everyone can see this', NULL),
(2, 'Only authenticated users can see this', NULL),
(3, 'Only user with specific id can see this', NULL);
ALTER TABLE data ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read" ON "public"."data" TO public
USING (id = 1);
CREATE POLICY "Authenticated access" ON "public"."data" TO authenticated
USING (id = 2);
CREATE POLICY "User access" ON "public"."data" TO authenticated
USING (id = 3 AND auth.uid() = user_id);
Install Hexclave and Supabase dependencies
npx create-next-app@latest -e with-supabase hexclave-supabase
cd hexclave-supabase
npx @hexclave/cli@latest init
.env.local:NEXT_PUBLIC_SUPABASE_URL=<your-supabase-url>
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-supabase-anon-key>
SUPABASE_JWT_SECRET=<your-supabase-jwt-secret>
# The project ID is the only client-exposed Hexclave variable; in Next.js it must
# be prefixed with NEXT_PUBLIC_. HEXCLAVE_SECRET_SERVER_KEY is server-only and must
# NEVER be prefixed or exposed to the client.
NEXT_PUBLIC_HEXCLAVE_PROJECT_ID=<your-hexclave-project-id>
HEXCLAVE_SECRET_SERVER_KEY=<your-secret-server-key>
Mint Supabase JWTs from Hexclave users
'use server';
import { hexclaveServerApp } from "@/hexclave/server";
import * as jose from "jose";
export const getSupabaseJwt = async () => {
const user = await hexclaveServerApp.getUser();
if (!user) {
return null;
}
const token = await new jose.SignJWT({
sub: user.id,
role: "authenticated",
})
.setProtectedHeader({ alg: "HS256" })
.setIssuedAt()
.setExpirationTime("1h")
.sign(new TextEncoder().encode(process.env.SUPABASE_JWT_SECRET));
return token;
};
Create a Supabase client that uses the Hexclave JWT
import { createBrowserClient } from "@supabase/ssr";
import { getSupabaseJwt } from "./actions";
export const createSupabaseClient = () => {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ accessToken: async () => await getSupabaseJwt() || "" },
);
};
Fetch Supabase data
'use client';
import { createSupabaseClient } from "@/utils/supabase-client";
import { useHexclaveApp, useUser } from "@hexclave/next";
import Link from "next/link";
import { useEffect, useState } from "react";
export default function Page() {
const app = useHexclaveApp();
const user = useUser();
const supabase = createSupabaseClient();
const [data, setData] = useState<null | any[]>(null);
useEffect(() => {
supabase.from("data").select().then(({ data }) => setData(data ?? []));
}, []);
const listContent = data === null
? <p>Loading...</p>
: data.length === 0
? <p>No notes found</p>
: data.map((note) => <li key={note.id}>{note.text}</li>);
return (
<div>
{user ? (
<>
<p>You are signed in</p>
<p>User ID: {user.id}</p>
<Link href={app.urls.signOut}>Sign Out</Link>
</>
) : (
<Link href={app.urls.signIn}>Sign In</Link>
)}
<h3>Supabase data</h3>
<ul>{listContent}</ul>
</div>
);
}
CLI Setup
Follow these instructions to authenticate users in a command line application with Hexclave.Add the CLI auth template
hexclave_cli_template.py.Example project layout:my-python-app/
├─ main.py
└─ hexclave_cli_template.py
Prompt the user to log in
prompt_cli_login. It opens the browser, lets the user authenticate, and returns a refresh token.from hexclave_cli_template import prompt_cli_login
refresh_token = prompt_cli_login(
app_url="https://your-app-url.example.com",
project_id="your-project-id-here",
publishable_client_key="your-publishable-client-key-here",
)
if refresh_token is None:
print("User cancelled the login process. Exiting")
exit(1)
Exchange the refresh token for an access token
def get_access_token(refresh_token):
access_token_response = hexclave_request(
"post",
"/api/v1/auth/sessions/current/refresh",
headers={
"x-hexclave-refresh-token": refresh_token,
},
)
return access_token_response["access_token"]
Fetch the current user
def get_user_object(access_token):
return hexclave_request(
"get",
"/api/v1/users/me",
headers={
"x-hexclave-access-token": access_token,
},
)
user = get_user_object(get_access_token(refresh_token))
print("The user is logged in as", user["display_name"] or user["primary_email"])