Start
Get a signed-in user.
Two ways in. Build sign-in from scratch, or bring an app that already has users. Both end with a working session in your app.
- From zero to a signed-in user. Five frameworks, one copy-paste path each. Install the stock better-auth client and point it at your instance.
- Moving from another provider. What to carry across from Clerk, and what changes.
Quickstart
From zero to a signed-in user.
There is no Signet SDK to learn. Install the stock better-auth client, point it at your instance’s /api/auth, and the calls you already write just work. Five actual frameworks, one copy-paste path each, plus React and vanilla-client foundations.
import { createAuthClient } from "better-auth/client";
// Your existing better-auth client: point baseURL
// at your Signet instance. The wire is the contract.
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// The same calls you already write. They just work.
await authClient.signIn.email({ email, password });Three constants, every framework.
Whatever you build with, the path is the same three moves. The frameworks below differ only in where they hold state.
- Install the stock client:
bun add better-auth(ornpm i better-auth). No Signet package. - Point
baseURLat your instance’s/api/auth. The requests are identical, hosted or on-prem. - Call the methods you already know:
signUp.email,signIn.email,useSession,getSession,signOut.
id_token_signed_response_alg selects an available active signing algorithm. Discovery lists the available algorithms with the default first. New installs default an omitted value to RS256; migrated installs with an existing signing key stay explicitly pinned to EdDSA. See the OAuth provider guide before choosing your client's setting.Next.js · App Router
The React client (better-auth/react) gives you signIn.email and the useSession hook inside your "use client" components.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import { createAuthClient } from "better-auth/react";
// One client for the whole app: the stock better-auth
// React client, pointed at your Signet instance.
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// In a "use client" component: sign in, then read the
// session with the hook. Same calls you already write.
await authClient.signIn.email({ email, password });
const { data, isPending } = authClient.useSession();Browser clients should call /api/auth on their own origin, as the Next.js starter demonstrates with a same-origin gateway; when the app and Signet use different origins, add the app's origin to the instance's [server].trusted_origins.
To read the session in a Server Component or Route Handler, forward the request cookies with the vanilla better-auth/client, as shown in the React Router v7 card.
React Router v7
There is no React-Router-specific better-auth package, and none is needed: use the React client in components, and the vanilla client inside a server loader to read the session with the incoming request headers.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
// app/lib/auth-client.ts: the React client for components.
import { createAuthClient as createReactAuthClient } from "better-auth/react";
export const authClient = createReactAuthClient({ baseURL: "https://auth.example.com/api/auth" });
await authClient.signIn.email({ email, password });
// app/routes/dashboard.tsx: read the session in a loader by
// forwarding the request cookies to your Signet instance.
import { createAuthClient as createServerAuthClient } from "better-auth/client";
const serverAuth = createServerAuthClient({ baseURL: "https://auth.example.com/api/auth" });
export async function loader({ request }) {
const session = await serverAuth.getSession({
fetchOptions: { headers: request.headers },
});
if (!session.data) throw redirect("/login");
return { user: session.data.user };
}Gate any route by redirecting when session.data is null; the loader runs on the server, so the check never reaches the browser.
Node / Express · session verification
Your backend becomes a resource server. The vanilla better-auth/client forwards the caller’s session cookie to Signet and reads session.data.user: Signet holds the credentials, your API just checks the session.
Install the stock client: npm i better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import express from "express";
import { createAuthClient } from "better-auth/client";
const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// Verify the caller's session against Signet on each request.
async function requireUser(req, res, next) {
const session = await authClient.getSession({
fetchOptions: { headers: { cookie: req.headers.cookie ?? "" } },
});
if (!session.data) return res.status(401).json({ error: "not signed in" });
req.user = session.data.user;
next();
}Attach requireUser to any route that needs a signed-in caller; a missing or expired session returns 401 without your backend ever storing a password.
Vue 3
The stock package has a dedicated better-auth/vue entry point. Its useSession state is a Vue ref, so sign-in and reactive session rendering use the framework’s native model.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import { createAuthClient } from "better-auth/vue";
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// In a Vue setup block: useSession() returns a Vue ref.
const session = authClient.useSession();
await authClient.signIn.email({ email, password });
// In the template: session.data?.userUse session.value in script and Vue’s automatic ref unwrapping in templates. The HTTP calls remain the same certified wire.
Svelte
The stock better-auth/svelte entry point exposes session state as a nanostore. Svelte’s $session subscription updates after the same signIn.email call.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import { createAuthClient } from "better-auth/svelte";
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// In a component module: Svelte auto-subscribes with $session.
const session = authClient.useSession();
await authClient.signIn.email({ email, password });
// In markup: {$session.data?.user.email}For SvelteKit, keep the browser client shown here and put the same-origin /api/auth gateway at the framework boundary; Signet remains the auth server.
React · single-page client foundation
React itself is the client library under the Next.js and React Router paths above. This supplemental recipe isolates better-auth/react: signUp.email, useSession, and signOut.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// Create an account (swap for signIn.email to log in).
await authClient.signUp.email({ email, password, name });
// Read the session with the hook; sign out when done.
const { data, isPending } = authClient.useSession();
await authClient.signOut();Browser clients should call /api/auth on their own origin, as the Next.js starter demonstrates with a same-origin gateway; when the app and Signet use different origins, add the app's origin to the instance's [server].trusted_origins.
The Express starter demonstrates session verification on the server with the incoming request cookies.
Plain JavaScript · no framework
The vanilla client (better-auth/client) is the one every other quickstart builds on: createAuthClient, signIn.email, getSession, signOut. It runs in any JavaScript runtime.
Install the stock client: bun add better-auth. Nothing Signet-specific to add; the client package is the integration path.
Pinned client: better-auth 1.6.23. The certification receipt covers this version exactly; newer clients are not known to break and are not covered.
import { createAuthClient } from "better-auth/client";
const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// Every call returns { data, error }. It does not throw.
const { data, error } = await authClient.signIn.email({ email, password });
// Read the current session; sign out to end it.
const session = await authClient.getSession();
await authClient.signOut();This is the whole integration surface. Any framework is this client plus that framework’s own way of holding state. There is nothing Signet-specific to learn.
Two runnable starters.
Your Signet delivery includes two standalone, secret-free apps. Each has its own manifest, setup guide, and executable smoke test against a local Signet stub.
- The Next.js starter ships with your Signet delivery at
examples/starters/next-app(hosted onboarding or the enterprise source delivery); there is no public download. It includes an App Router sign-up/sign-in page plus a same-origin/api/auth/*gateway that preserves eachSet-Cookieheader. - The Express starter ships in the same delivery at
examples/starters/express-api. Its/api/meguard forwards the caller’s cookie through the stockbetter-auth/client.
Run npm ci && npm test in either directory. Set only the public SIGNET_URL; neither starter contains a server secret, database credential, or Signet-specific SDK.
Why there is no Signet SDK.
The stock better-auth client is the integration. Open if you want the reason, and the ADK.
better-auth/client for server-side session reads. Every method shown traces to better-auth 1.6.23, the release Signet is certified against (compatibility gap 0: scoped to the checks in the public compatibility profile, not a claim that every better-auth route is implemented; the full statement is on /compatibility). What Signet ships instead is an ADK, an AI Development Kit: the agent on-ramp served by the engine itself (/llms.txt and /llms-full.txt, version-matched and air-gap capable, plus the OpenAPI schema and the machine-readable certification receipt), so an agent can wire this integration without a library to learn. Since v0.1.0 the ADK also has an executable form: signetctl agent runs that loop from your terminal against your own OpenAI-compatible endpoint, and signetctl mcp serve exposes the same operator verbs to any MCP client; the reference is on /signetctl.Docs that live inside the engine.
Every deployed instance serves its own /docs and certification receipt from inside the engine, so the reference always matches the build you are running, even on a host with no internet. Get an instance and point your client at it.