Quickstart
Add authentication to your app in under 5 minutes.
1. Install the SDK
For Next.js:
npm install @bulwarkauth/nextjs
# or
pnpm add @bulwarkauth/nextjs
For plain React:
npm install @bulwarkauth/react
2. Get your publishable key
- Go to app.bulwarkauth.com
- Use the app switcher in the top navigation to select your application
- Navigate to Configure > API Keys
- Copy the
pk_live_...key (orpk_test_...for development)
Each application in your workspace has its own publishable and secret key pair. Make sure you have the correct app selected before copying keys.
Publishable keys are safe to include in client-side code. They identify your app but cannot perform admin operations. See Publishable Keys for details.
Zero-config CORS: When your SDK sends the publishable key, CORS is handled automatically. No domains to configure — new subdomains, staging environments, and localhost all work out of the box. See CORS for details.
3. Wrap your app with BulwarkProvider
Next.js (app/layout.tsx):
import { CookieAwareBulwarkProvider } from "@bulwarkauth/nextjs";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<CookieAwareBulwarkProvider publishableKey="pk_live_...">
{children}
</CookieAwareBulwarkProvider>
</body>
</html>
);
}
React (src/main.tsx):
import { BulwarkProvider } from "@bulwarkauth/react";
ReactDOM.createRoot(document.getElementById("root")!).render(
<BulwarkProvider publishableKey="pk_live_...">
<App />
</BulwarkProvider>
);
4. Add sign-in and sign-up pages
// app/login/page.tsx
import { SignIn } from "@bulwarkauth/nextjs";
export default function LoginPage() {
return <SignIn />;
}
// app/signup/page.tsx
import { SignUp } from "@bulwarkauth/nextjs";
export default function SignUpPage() {
return <SignUp />;
}
5. Add UserButton to your header
// app/components/Header.tsx
"use client";
import { UserButton } from "@bulwarkauth/nextjs";
export function Header() {
return (
<header>
<nav>
<a href="/">Home</a>
<UserButton afterSignOutUrl="/" />
</nav>
</header>
);
}
UserButton renders an avatar with a dropdown for profile and sign-out. It renders nothing when the user is signed out.
6. Protect routes
Next.js middleware (middleware.ts at the project root):
import { createBulwarkMiddleware } from "@bulwarkauth/nextjs/middleware";
export default createBulwarkMiddleware({
protectedPaths: ["/dashboard", "/settings"],
publicPaths: ["/", "/login", "/signup"],
loginPath: "/login",
});
export const config = {
matcher: ["/((?!_next|static|favicon.ico).*)"],
};
React (ProtectedRoute):
import { ProtectedRoute } from "@bulwarkauth/react";
function App() {
return (
<Routes>
<Route path="/dashboard" element={
<ProtectedRoute fallback={<Navigate to="/login" />}>
<Dashboard />
</ProtectedRoute>
} />
</Routes>
);
}
7. Read the user in Server Components
// app/dashboard/page.tsx
import { auth } from "@bulwarkauth/nextjs/server";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const { user } = await auth();
if (!user) {
redirect("/login");
}
return <h1>Welcome, {user.display_name}</h1>;
}