Authentication
Better Auth across web, mobile, and API
Every project with an API gets Better Auth — email/password, optional OAuth, typed sessions, and auth pages on every platform.
What's generated
apps/api/src/lib/auth.ts — Better Auth config with Drizzle adapter, email/password, OAuth providers, 7-day sessions.
apps/api/src/middleware/session.ts — two middleware:
// Extracts session — sets c.get("user") and c.get("session")
export const sessionMiddleware = createMiddleware<AppEnv>(async (c, next) => {
const session = await auth.api.getSession({
headers: c.req.raw.headers,
});
c.set("user", session?.user ?? null);
c.set("session", session?.session ?? null);
await next();
});
// Blocks unauthenticated requests
export const requireAuth = createMiddleware<AppEnv>(async (c, next) => {
const user = c.get("user");
if (!user) return c.json({ error: "Unauthorized" }, 401);
await next();
});apps/api/src/types.ts — typed context so c.get("user") returns { id, email, name }:
export type AppEnv = {
Variables: {
user: { id: string; email: string; name: string } | null;
session: { id: string; expiresAt: Date } | null;
};
};Three auth pages under (auth)/:
- Sign in — email/password form + OAuth buttons (Google, GitHub, Apple)
- Sign up — registration with name, email, password
- Forgot password — password reset flow
All are "use client" components with loading states, error handling, and i18n-aware navigation.
src/lib/auth-client.ts — Better Auth client:
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001",
});Use authClient.useSession(), authClient.signIn.email(), authClient.signUp.email(), authClient.signOut().
Two auth screens under app/(auth)/:
- Sign in — email/password + social buttons
- Sign up — registration
Both use the Better Auth React Native client at lib/auth-client.ts.
import { createAuthClient } from "better-auth/react";
export const authClient = createAuthClient({
baseURL: process.env.EXPO_PUBLIC_API_URL || "http://localhost:3001",
});OAuth providers
Select during coldstart init or add later:
coldstart add auth --providers google,github,appleEach provider needs environment variables, validated at startup:
| Provider | Variables |
|---|---|
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | |
| GitHub | GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET |
| Apple | APPLE_CLIENT_ID, APPLE_CLIENT_SECRET |
OAuth buttons are automatically added to sign-in and sign-up pages on both web and mobile.
Multi-tenant & RBAC
Enable multi-tenant for organization support:
coldstart add tenantThis generates:
- Database tables:
organization,member(with role),invitation(with token + expiry) - Organization middleware: extracts org from
x-organization-slugheader, verifies membership - RBAC middleware:
requireRole("admin")checks role hierarchy (owner > admin > member > viewer)
app.use("/org/:orgSlug/*", organizationMiddleware);
app.use("/org/:orgSlug/settings/*", requireRole("admin"));
app.delete("/org/:orgSlug", requireRole("owner"), deleteOrg);Per-seat billing auto-enables multi-tenant and RBAC.