Integrations
Authentication
Choose Better Auth or Clerk for Bunship authentication.
Bunship supports two auth providers:
- Better Auth (default, fully integrated auth + MFA + passkeys + API keys)
- Clerk (managed auth UI + user sync via webhook)
Choose the provider by setting NEXT_PUBLIC_AUTH_PROVIDER in your environment. If not set, Bunship defaults to better-auth.
Setup
Follow the section that matches your provider.
1. Choose provider (default: Better Auth)
# Better Auth (default)
NEXT_PUBLIC_AUTH_PROVIDER=better-auth
# Clerk
NEXT_PUBLIC_AUTH_PROVIDER=clerk2. Better Auth setup
Generate Better Auth Secret
BETTER_AUTH_SECRET is used for session and token signing.
openssl rand -base64 32Add to .env:
BETTER_AUTH_SECRET="YOUR-BETTER-AUTH-SECRET"
BETTER_AUTH_URL="http://localhost:3001"Configure GitHub OAuth
Create a GitHub OAuth App and set callback URLs:
- Local:
http://localhost:3001/api/v1/auth/callback/github - Production:
https://YOUR_DOMAIN/api/v1/auth/callback/github
Add to .env:
OAUTH_GITHUB_CLIENT_ID="YOUR-GITHUB-CLIENT-ID"
OAUTH_GITHUB_CLIENT_SECRET="YOUR-GITHUB-CLIENT-SECRET"Use separate OAuth apps for development and production environments.
Configure Google OAuth
Create a Google OAuth client and set callback URLs:
- Local:
http://localhost:3001/api/v1/auth/callback/google - Production:
https://YOUR_DOMAIN/api/v1/auth/callback/google
Add to .env:
OAUTH_GOOGLE_CLIENT_ID="YOUR-GOOGLE-CLIENT-ID"
OAUTH_GOOGLE_CLIENT_SECRET="YOUR-GOOGLE-CLIENT-SECRET"
NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID="YOUR-GOOGLE-CLIENT-ID"Enable credential login
Email/password login requires email delivery to be configured first.
3. Clerk setup
- Create a Clerk application.
- Add the following environment variables:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="YOUR-CLERK-PUBLISHABLE-KEY"
CLERK_SECRET_KEY="YOUR-CLERK-SECRET-KEY"
CLERK_WEBHOOK_SECRET="YOUR-CLERK-WEBHOOK-SECRET"- Configure Clerk webhooks to sync users into the Bunship database:
- Endpoint:
https://YOUR_DOMAIN/api/v1/webhook/clerk - Events:
user.created,user.updated,user.deleted
Core Features
- Email auth and verification flow
- Google and GitHub social login
- Account linking across auth methods
- Invitation attribution for email and OAuth signup
- Automatic wallet initialization for new users
Better Auth only:
- MFA and passkey support
- API key management
Client-Side Usage
Access session
'use client';
import { authClient } from '@/lib/auth-client';
export function ProfileButton() {
const { data: session, isPending } = authClient.useSession();
if (isPending) return <div>Loading...</div>;
if (!session?.user) return <button>Sign in</button>;
return <button>{session.user.name}</button>;
}Auth operations
authClient.signIn.* APIs are Better Auth only. In Clerk mode, use Clerk UI components like SignIn / SignUp.
import { authClient } from '@/lib/auth-client';
await authClient.signIn.email({
email: 'user@example.com',
password: 'password123',
});
await authClient.signIn.social({
provider: 'google',
callbackURL: '/',
});
await authClient.signOut();Server-Side Usage
Route protection
import { getSession } from '@/lib/session';
import { redirect } from 'next/navigation';
export default async function ProtectedPage() {
const session = await getSession();
if (!session?.user) {
redirect('/signin');
}
return <div>Protected content</div>;
}Admin-only guard
import { getSession } from '@/lib/session';
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const session = await getSession();
if (!session?.user || session.user.role !== 'admin') {
redirect('/signin');
}
return <div>Admin content</div>;
}Best Practices
- Keep OAuth apps and secrets separate by environment.
- Keep callback URLs aligned with deployment domains.
- Enforce role checks server-side for sensitive routes.
- Debug auth failures from callback URL + cookie policy + env consistency.
- For Clerk, ensure webhook events are delivered and idempotent.