Skip to Content
Puzzle
Developer

Authentication Setup

Configure the Puzzle Auth client and server integrations generated by @puzzle-ui/create.

Puzzle Auth consists of two packages with separate responsibilities:

  • @puzzle-ui/auth contains framework-independent authentication logic.
  • @puzzle-ui/fullstack provides the browser client, React components, HTTP handlers, and framework adapters.

The project generator can scaffold the client integration and framework API route for Next.js and TanStack Start.

Security configuration is required

The generated authentication integration is not production-ready by itself. You must supply secure storage, password hashing, rate limiting, session, MFA, cookie, CSRF, and trusted client IP configuration before exposing authentication routes.

Generate an application

Run the Puzzle project generator:

npx @puzzle-ui/create

Choose Next.js or TanStack Start and enable Puzzle Auth.

The generator installs:

npm install @puzzle-ui/auth @puzzle-ui/fullstack @puzzle-ui/session

Generated client integration

The generator wraps the application in AuthProvider.

import { AuthProvider } from "@puzzle-ui/fullstack/auth/client";

export const Providers = ({ children }: { children: React.ReactNode }) => (
  <AuthProvider options={{ basePath: "/api/auth" }}>{children}</AuthProvider>
);

The provider creates the browser authentication client and retrieves authentication state from the server.

Session credentials are managed by secure server cookies. Do not copy session tokens into local storage or session storage.

Authentication pages

The generator creates sign-in and sign-up pages using AuthExperience.

import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";

export const SignInPage = () => <AuthExperience mode="sign-in" />;
import { AuthExperience } from "@puzzle-ui/fullstack/auth/client";

export const SignUpPage = () => <AuthExperience mode="sign-up" />;

The experience supports branding, layout, redirects, custom registration fields, and custom submission handling.

See the @puzzle-ui/fullstack package documentation for the complete AuthExperience API.

Framework API routes

Next.js

The generator creates:

src/app/api/auth/[...auth]/route.ts

The route delegates to createNextAuthHandler.

import { createNextAuthHandler } from "@puzzle-ui/fullstack/auth/next";

const handlers = createNextAuthHandler({
  auth: authServer,
});

export const GET = handlers.GET;
export const POST = handlers.POST;

The generated route also calls the application bootstrap and returns HTTP 503 until an AuthServer has been registered.

TanStack Start

The generator creates:

src/routes/api/auth/$.ts

The route delegates to createTanStackAuthHandler through the TanStack server route handlers.

Both adapters delegate authentication policy and security-sensitive behavior to the framework-independent authentication packages.

Basic React

A Basic React project has no server runtime.

The generator creates the AuthProvider and sign-in/sign-up components, but it does not generate a server API route.

Host the Puzzle Auth API in a separate server application. Configure the client base path to point to that API.

Configure the server

The generated Next.js and TanStack Start projects include these server-only files:

src/lib/auth/
├── server.ts
├── bootstrap.ts
└── unavailable.ts

The server.ts module exposes two functions:

  • configureAuthServer(server) registers the configured server.
  • getAuthServer() returns the registered server or null.

The bootstrap module provides one initialization point. It is intentionally left for your application to complete.

Create the AuthServer

The fullstack package expects an AuthServer assembled from the authentication managers and session configuration.

import { createAuthServer } from "@puzzle-ui/fullstack/auth/server";

import { configureAuthServer } from "./server";

import {
  auth,
  mfa,
  stepUp,
  sessions,
  cookie,
  csrf,
  resolveClientIp,
} from "./auth-managers";

export const initializePuzzleAuth = () => {
  configureAuthServer(
    createAuthServer({
      auth,
      mfa,
      stepUp,
      sessions,
      cookie,
      csrf,
      resolveClientIp,
    }),
  );
};

This example assumes that auth-managers exports already initialized and correctly configured dependencies. It is not a complete provider implementation.

Call your application initialization from the generated bootstrap function. Ensure that initialization is safe to run once per server runtime.

Required security dependencies

Storage

The storage adapter must support the capabilities required by the authentication and session managers.

At minimum, verify:

  • Unique constraints.
  • Conditional writes.
  • Atomic batch operations.

Do not use an in-memory adapter for production sessions, tokens, MFA factors, or other security-critical state.

Password hashing

Supply a secure password hashing implementation through the PasswordHasher interface.

Do not store plaintext passwords. Do not replace the password hasher with a fast general-purpose hash such as SHA-256.

Rate limiting

Supply a shared atomic rate limiter. A process-local counter is not sufficient for production deployments with multiple instances.

Session management

Create a StorageSessionManager using the same storage adapter and configure appropriate idle and absolute session lifetimes.

MFA

The MFA manager requires:

  • A password hasher.
  • A rate-limit provider.
  • An authenticated session manager.
  • A secret protector for TOTP secrets.
  • A WebAuthn provider when passkeys are enabled.

The WebAuthn relying-party ID, name, and origin must match the actual deployment.

Cookies and CSRF

Use secure, HttpOnly cookies in production. Configure CSRF protection with the application's trusted origins.

Client IP resolution

The resolveClientIp callback must use the deployment's trusted proxy configuration.

Do not blindly trust arbitrary X-Forwarded-For values.

HTTP 503 before configuration

The generated API route deliberately returns a no-store HTTP 503 response when the application has not registered an AuthServer.

This prevents a generated but unconfigured authentication endpoint from appearing to work.

Do not remove this protection or replace it with fake managers.

Client and server boundaries

Keep these imports separate:

CodeAllowed entry point
Browser components and hooks@puzzle-ui/fullstack/auth/client
Server handlers@puzzle-ui/fullstack/auth/server
Next.js adapter@puzzle-ui/fullstack/auth/next
TanStack Start adapter@puzzle-ui/fullstack/auth/tanstack
Shared serializable contracts@puzzle-ui/fullstack/auth/shared

Never import server handlers, storage adapters, password hashing implementations, or secrets into browser-facing modules.

Basic React with a separate API

For a browser-only React application, point the AuthProvider to the server API:

<AuthProvider
  options={{
    basePath: "https://api.example.com/api/auth",
    credentials: "include",
  }}
>
  <App />
</AuthProvider>

The API deployment must configure CORS, trusted origins, cookies, and CSRF protection for the browser application's origin.

Further reading

;