@startupkit/auth
v0.5.4
Published
Auth package for StartupKit
Readme
@startupkit/auth
Lightweight Authentication and Authorization components and hooks for StartupKit projects.
Part of StartupKit - The Zero to One Startup Framework.
Installation
pnpm add @startupkit/auth better-authOr use the StartupKit CLI to get started with a complete monorepo setup:
npx startupkit initWhat's Included
This package provides lightweight wrappers around Better Auth:
- 🎨
AuthProvider- React context provider for client components - 🪝
useAuth()- Authentication hook for client components - 🔒 Full TypeScript support
You call betterAuth() directly in your project for full control over configuration.
Usage
1. Configure Better Auth (Server-Side)
Create your auth configuration with Better Auth directly:
// lib/auth.ts
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { nextCookies } from "better-auth/next-js"
import { emailOTP } from "better-auth/plugins"
import { db } from "@/lib/db"
export const auth = betterAuth({
basePath: "/auth",
database: drizzleAdapter(db, {
provider: "pg"
}),
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days
updateAge: 60 * 60 * 24 // Refresh every 24 hours
},
plugins: [
emailOTP({
sendVerificationOTP: async ({ email, otp }) => {
// Send OTP via your email provider
await sendEmail({
to: email,
subject: "Your verification code",
template: "otp",
data: { code: otp }
})
}
}),
nextCookies()
],
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
}
}
})2. Create API Route Handler
Create the auth API route at app/auth/[...all]/route.ts:
// app/auth/[...all]/route.ts
import { auth } from "@/lib/auth"
import { toNextJsHandler } from "better-auth/next-js"
export const { GET, POST } = toNextJsHandler(auth.handler)3. Create Auth Client (Client-Side)
Create your auth client using Better Auth:
// lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { emailOTPClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
basePath: "/auth",
plugins: [emailOTPClient()]
})4. Set Up Providers
Wrap your app with the AuthProvider from @startupkit/auth:
// app/providers.tsx
"use client"
import { AuthProvider } from "@startupkit/auth"
import { authClient } from "@/lib/auth-client"
interface ProvidersProps {
children: React.ReactNode
user?: User
}
export function Providers({ children, user }: ProvidersProps) {
return (
<AuthProvider
authClient={authClient}
user={user}
onIdentify={(user) => {
// Optional: Track user identification (e.g., analytics)
console.log("User identified:", user)
}}
onReset={() => {
// Optional: Reset state on logout (e.g., clear analytics)
console.log("User logged out")
}}
>
{children}
</AuthProvider>
)
}Pass the user from your root layout:
// app/layout.tsx
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { Providers } from "./providers"
export default async function RootLayout({ children }) {
const session = await auth.api.getSession({
headers: await headers()
})
return (
<html>
<body>
<Providers user={session?.user}>
{children}
</Providers>
</body>
</html>
)
}5. Use Authentication in Components
Access authentication state and methods with the useAuth hook:
"use client"
import { useAuth } from "@startupkit/auth"
export function UserProfile() {
const { isAuthenticated, isLoading, user, logout } = useAuth()
if (isLoading) {
return <div>Loading...</div>
}
if (!isAuthenticated) {
return <a href="/sign-in">Sign In</a>
}
return (
<div>
<p>Welcome, {user.name}</p>
<button onClick={logout}>Sign Out</button>
</div>
)
}Authentication Methods
Email OTP (One-Time Password)
"use client"
import { useAuth } from "@startupkit/auth"
import { useState } from "react"
export function EmailSignIn() {
const { sendAuthCode, verifyAuthCode } = useAuth()
const [email, setEmail] = useState("")
const [code, setCode] = useState("")
const [step, setStep] = useState<"email" | "code">("email")
const handleSendCode = async (e: React.FormEvent) => {
e.preventDefault()
await sendAuthCode(email)
setStep("code")
}
const handleVerifyCode = async (e: React.FormEvent) => {
e.preventDefault()
await verifyAuthCode(email, code)
// User is now authenticated
}
if (step === "email") {
return (
<form onSubmit={handleSendCode}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
/>
<button type="submit">Send Code</button>
</form>
)
}
return (
<form onSubmit={handleVerifyCode}>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="Enter verification code"
required
/>
<button type="submit">Verify</button>
</form>
)
}Google OAuth
"use client"
import { useAuth } from "@startupkit/auth"
export function GoogleSignIn() {
const { googleAuth } = useAuth()
return (
<button onClick={googleAuth}>
Sign in with Google
</button>
)
}Sign Out
"use client"
import { useAuth } from "@startupkit/auth"
export function SignOutButton() {
const { logout } = useAuth()
return (
<button onClick={logout}>
Sign Out
</button>
)
}Server-Side Authentication
Protect Server Components
// app/dashboard/page.tsx
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { redirect } from "next/navigation"
export default async function DashboardPage() {
const session = await auth.api.getSession({
headers: await headers()
})
if (!session) {
redirect("/sign-in")
}
return (
<div>
<h1>Dashboard</h1>
<p>Welcome, {session.user.name}</p>
</div>
)
}Use in API Routes
// app/api/profile/route.ts
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { NextResponse } from "next/server"
export async function GET() {
const session = await auth.api.getSession({
headers: await headers()
})
if (!session) {
return NextResponse.json(
{ error: "Unauthorized" },
{ status: 401 }
)
}
return NextResponse.json({
user: session.user
})
}Features
Supported Authentication Methods
- ✅ Email OTP - One-time password via email (10-minute expiration)
- ✅ Google OAuth - Sign in with Google
- ✅ Session Management - 7-day sessions with 24-hour auto-refresh
- ✅ TypeScript - Full type safety
Built With
This package is a lightweight wrapper around Better Auth, providing:
- React context and hooks for easy integration
- Server utilities for Next.js
- TypeScript type definitions
- Minimal configuration required
API Reference
Client Exports
AuthProvider
React context provider wrapping Better Auth client.
interface AuthProviderProps {
children: React.ReactNode
user?: User
authClient: BetterAuthClient
onIdentify?: (user: User) => void
onReset?: () => void
}useAuth()
Hook to access authentication state and methods.
const {
isAuthenticated, // boolean - Is user authenticated?
isLoading, // boolean - Is session loading?
user, // User | null | undefined - Current user
logout, // () => Promise<void> - Sign out user
sendAuthCode, // (email: string) => Promise<void> - Send OTP
verifyAuthCode, // (email: string, code: string) => Promise<void> - Verify OTP
googleAuth // () => Promise<void> - Sign in with Google
} = useAuth()AuthContext
React context (if you need direct access).
import { AuthContext } from "@startupkit/auth"Configuration
All authentication configuration happens in Better Auth directly. See the Better Auth documentation for complete configuration options including:
- Email/password authentication
- Social providers (Google, GitHub, etc.)
- Magic links
- Two-factor authentication
- Custom database adapters
- Hooks and middleware
Environment Variables
Required for Google OAuth:
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secretLearn More
- StartupKit Website: startupkit.com
- GitHub Repository: github.com/ian/startupkit
- Better Auth Docs: better-auth.com/docs
- Full Documentation: startupkit.com
Support
Having issues? Open an issue on GitHub
License
ISC © 2025 01 Studio
