This guide wires the smallest useful Next.js setup: a BolkAuth engine, route handler, React provider, and middleware.
Create lib/auth.ts:
import { createBolkAuth } from "@bolkauth/core";
import { createDrizzleAdapter } from "@bolkauth/adapter-drizzle/pg";
import { db } from "@/db";
export const auth = createBolkAuth({
adapter: createDrizzleAdapter(db),
secret: process.env.BOLKAUTH_SECRET!,
session: {
maxAge: 60 * 60 * 24 * 30,
cookieName: "bolkauth.session",
},
emailAndPassword: {
enabled: true,
minPasswordLength: 8,
},
});
Use the adapter import that matches your database. See Adapters for Drizzle, Prisma, MongoDB, and custom adapter setup.
Create app/api/auth/[...bolkauth]/route.ts:
import { bolkAuthHandler } from "@bolkauth/nextjs";
import { auth } from "@/lib/auth";
const handlers = bolkAuthHandler(auth);
export const GET = handlers.GET;
export const POST = handlers.POST;
export const PATCH = handlers.PATCH;
export const DELETE = handlers.DELETE;
export const OPTIONS = handlers.OPTIONS;
Wrap your app in app/layout.tsx:
import { BolkAuthProvider } from "@bolkauth/react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<BolkAuthProvider config={{ baseURL: "/api/auth" }}>
{children}
</BolkAuthProvider>
</body>
</html>
);
}
Create middleware.ts at the project root:
import { bolkAuthMiddleware } from "@bolkauth/nextjs";
import { auth } from "@/lib/auth";
export default bolkAuthMiddleware(auth, {
signInUrl: "/sign-in",
onboardingUrl: "/onboarding",
publicRoutes: ["/", "/sign-in", "/sign-up", "/api/auth"],
});
export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
};
"use client";
import { useSignIn } from "@bolkauth/react";
import { useRouter } from "next/navigation";
import { useState } from "react";
export function SignInForm() {
const router = useRouter();
const { signIn, isLoading, error, fieldErrors } = useSignIn();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
async function onSubmit(event: React.FormEvent) {
event.preventDefault();
const result = await signIn({ email, password });
if (!result.error) {
router.push("/dashboard");
router.refresh();
}
}
return (
<form onSubmit={onSubmit}>
<input value={email} onChange={(event) => setEmail(event.target.value)} type="email" />
<input value={password} onChange={(event) => setPassword(event.target.value)} type="password" />
{fieldErrors.email && <p>{fieldErrors.email}</p>}
{error && <p>{error.message}</p>}
<button disabled={isLoading}>{isLoading ? "Signing in..." : "Sign in"}</button>
</form>
);
}