@bulwarkauth/react
React components and hooks for Bulwark authentication.
Installation
npm install @bulwarkauth/react
# or
pnpm add @bulwarkauth/react
BulwarkProvider
Wrap your application tree with BulwarkProvider. All hooks and components must be descendants of this provider.
import { BulwarkProvider } from "@bulwarkauth/react";
export default function App({ children }: { children: React.ReactNode }) {
return (
<BulwarkProvider publishableKey="pk_live_...">
{children}
</BulwarkProvider>
);
}
Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| publishableKey | string | Preferred | Your pk_live_ or pk_test_ key |
| config | BulwarkConfig | Legacy | Object with tenantId and baseUrl. Use publishableKey instead |
The publishableKey prop resolves your app's configuration (tenant, branding, enabled auth methods) from the /api/v1/auth/identify endpoint on initialization. Token refresh is handled automatically.
Pre-built Components
<SignIn />
Renders a complete sign-in form with email/password, magic link, and social login options based on your app's configuration.
import { SignIn } from "@bulwarkauth/react";
export default function LoginPage() {
return (
<SignIn
signUpUrl="/signup"
forgotPasswordUrl="/forgot-password"
onSignIn={(user) => console.log("Signed in:", user.id)}
/>
);
}
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| appearance | BulwarkAppearance | — | Theme and style overrides |
| onSignIn | (user: User) => void | — | Callback after successful sign-in |
| signUpUrl | string | — | Link shown at the bottom of the form |
| forgotPasswordUrl | string | — | Link for password reset flow |
| hideFooter | boolean | false | Hides the "Secured by Bulwark" footer |
<SignUp />
Renders a complete registration form.
import { SignUp } from "@bulwarkauth/react";
export default function SignUpPage() {
return (
<SignUp
signInUrl="/login"
onSignUp={(user) => console.log("Registered:", user.id)}
/>
);
}
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| appearance | BulwarkAppearance | — | Theme and style overrides |
| onSignUp | (user: User) => void | — | Callback after successful registration |
| signInUrl | string | — | Link shown at the bottom of the form |
| hideFooter | boolean | false | Hides the "Secured by Bulwark" footer |
<UserButton />
Renders an avatar button with a dropdown menu for profile navigation and sign-out. Renders nothing when signed out.
import { UserButton } from "@bulwarkauth/react";
function Header() {
return (
<nav>
<UserButton
afterSignOutUrl="/"
profileUrl="/settings/profile"
/>
</nav>
);
}
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| appearance | BulwarkAppearance | — | Theme and style overrides |
| afterSignOutUrl | string | "/" | Redirect URL after sign-out |
| onProfileClick | () => void | — | Override default profile navigation |
| profileUrl | string | — | URL for the profile page link |
<UserProfile />
Renders a full profile management UI (email, display name, avatar, password change, MFA setup).
import { UserProfile } from "@bulwarkauth/react";
export default function ProfilePage() {
return <UserProfile appearance={{ theme: "light" }} />;
}
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| appearance | BulwarkAppearance | — | Theme and style overrides |
Hooks
useBulwark()
Returns the full Bulwark context. Use this when you need low-level access to the client or need to trigger a user refresh.
import { useBulwark } from "@bulwarkauth/react";
function Example() {
const { user, isAuthenticated, isLoading, refreshUser } = useBulwark();
if (isLoading) return <Spinner />;
if (!isAuthenticated) return null;
return (
<div>
<p>{user.email}</p>
<button onClick={refreshUser}>Refresh</button>
</div>
);
}
Return value
| Field | Type | Description |
|-------|------|-------------|
| client | BulwarkClient | The underlying API client instance |
| user | User \| null | The currently authenticated user |
| isAuthenticated | boolean | true when a valid session exists |
| isLoading | boolean | true during initial session resolution |
| appConfig | AppConfig \| null | Resolved app configuration from publishable key |
| setUser | (user: User \| null) => void | Manually update the user in context |
| refreshUser | () => Promise<void> | Re-fetch the current user from the API |
useAuth()
Returns auth action methods for building custom forms.
import { useAuth } from "@bulwarkauth/react";
function CustomLoginForm() {
const { login, isLoading, error } = useAuth();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = e.currentTarget;
await login({
email: form.email.value,
password: form.password.value,
});
};
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" />
<input name="password" type="password" />
{error && <p>{error.message}</p>}
<button type="submit" disabled={isLoading}>Sign in</button>
</form>
);
}
Return value
| Field | Type | Description |
|-------|------|-------------|
| register | (opts) => Promise<User> | Create a new account |
| login | (opts) => Promise<User> | Sign in with email + password |
| requestMagicLink | (email: string) => Promise<void> | Send a magic link email |
| verifyMagicLink | (token: string) => Promise<User> | Exchange magic link token for session |
| sendEmailOtp | (email: string) => Promise<void> | Send a one-time code |
| verifyEmailOtp | (email, code) => Promise<User> | Verify OTP and establish session |
| logout | () => Promise<void> | Sign out and clear session |
| isLoading | boolean | true during any in-flight request |
| error | BulwarkError \| null | Last error, cleared on next action |
useMFA()
Handles TOTP and WebAuthn MFA enrollment and verification.
import { useMFA } from "@bulwarkauth/react";
function MfaSetup() {
const { enrollTotp, verifyTotp, enrolledFactors } = useMFA();
}
usePasskey()
Handles passkey (WebAuthn) registration and authentication.
import { usePasskey } from "@bulwarkauth/react";
function PasskeyButton() {
const { registerPasskey, authenticateWithPasskey } = usePasskey();
}
useAgent()
Manages agent credential sessions from the client side.
import { useAgent } from "@bulwarkauth/react";
function AgentPanel() {
const { createSession, activeSession, revokeSession } = useAgent();
}
useAppConfig()
Returns the resolved application configuration for the current publishable key.
import { useAppConfig } from "@bulwarkauth/react";
function BrandedHeader() {
const config = useAppConfig();
return <img src={config?.branding.logoUrl} alt={config?.name} />;
}
ProtectedRoute
Wraps a route to require authentication. Renders fallback when the user is not signed in, or unauthorized when the user lacks a required role.
import { ProtectedRoute } from "@bulwarkauth/react";
function App() {
return (
<Routes>
<Route
path="/admin"
element={
<ProtectedRoute
roles={["admin"]}
fallback={<Navigate to="/login" />}
unauthorized={<div>Access denied</div>}
>
<AdminDashboard />
</ProtectedRoute>
}
/>
</Routes>
);
}
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| roles | string[] | — | Required roles. All listed roles must be present |
| fallback | ReactNode | null | Rendered when not authenticated |
| unauthorized | ReactNode | null | Rendered when authenticated but missing a required role |
Appearance customization
Pass a BulwarkAppearance object to any component's appearance prop.
const appearance: BulwarkAppearance = {
theme: "dark",
variables: {
colorPrimary: "#6366f1",
colorBackground: "#0f172a",
colorText: "#f1f5f9",
fontFamily: "Inter, sans-serif",
borderRadius: "8px",
},
elements: {
card: { boxShadow: "0 4px 32px rgba(0,0,0,0.4)" },
primaryButton: { fontWeight: "600" },
},
};
<SignIn appearance={appearance} />
BulwarkAppearance type
| Field | Type | Description |
|-------|------|-------------|
| theme | "light" \| "dark" | Base color scheme |
| variables | AppearanceVariables | CSS variable overrides |
| elements | Record<string, CSSProperties> | Per-element style overrides |
AppearanceVariables
| Variable | Description |
|----------|-------------|
| colorPrimary | Primary action color (buttons, links) |
| colorBackground | Card background color |
| colorText | Primary text color |
| colorDanger | Error/destructive state color |
| fontFamily | Font stack |
| borderRadius | Border radius applied to cards and inputs |
Token refresh
Access tokens are refreshed automatically before they expire. No manual intervention is required. The refresh runs in the background; components re-render only if the user object changes.