Detailed explanation of the authentication architecture.
┌─────────────────────────────────────────────────────────────┐
│ Frontend │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ React App (http://localhost:4000) │ │
│ │ ┌─────────────────┐ ┌──────────────────┐ │ │
│ │ │ useEmailAuth │ │ useAuth │ │ │
│ │ └────────┬────────┘ └────────┬─────────┘ │ │
│ │ │ │ │ │
│ │ └──────────┬──────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ authClient │ │ │
│ │ │ (Better Auth) │ │ │
│ │ └───────┬────────┘ │ │
│ └──────────────────────┼────────────────────────────────┘ │
│ │ │
│ /api/* proxy │
│ │ │
└─────────────────────────┼───────────────────────────────────┘
│
│ HTTP + Cookies
│
┌─────────────────────────▼───────────────────────────────────┐
│ Backend │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Hono Server │ │
│ │ Cloudflare Workers (:8787) or Node.js (:4200) │ │
│ │ │ │
│ │ ┌────────────────────┐ ┌──────────────────────┐ │ │
│ │ │ Better Auth Router │ │ Email Service │ │ │
│ │ │ /api/auth/* │ │ (Resend API) │ │ │
│ │ └─────────┬──────────┘ └──────────────────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ D1 (SQLite) │ │ │
│ │ │ Database │ │ │
│ │ └────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Option A: Cloudflare Option B: Traditional
┌──────────────────────┐ ┌──────────────────────┐
│ Cloudflare Workers │ │ Node.js / Bun │
│ + D1 (SQLite) │ │ + SQLite / PostgreSQL│
│ │ │ │
│ Entry: src/index.ts │ │ Entry: src/node.ts │
│ DB: Kysely + D1Dialect│ │ DB: bun:sqlite │
│ Deploy: wrangler │ │ Deploy: Docker / VPS │
└──────────────────────┘ └──────────────────────┘
User Frontend Backend
│ │ │
│ Sign Up │ │
├───────────────────►│ │
│ │ POST /api/auth/ │
│ │ sign-up/email │
│ ├────────────────────►│
│ │ │ Create user
│ │ │ Hash password
│ │ │ Send verify email
│ │ Set-Cookie │
│◄───────────────────┴─────────────────────┤
│ Logged in ✅ │ │
User Frontend Backend Provider
│ │ │ │
│ Click "Login" │ │ │
├───────────────────►│ │ │
│ │ POST /api/auth/ │ │
│ │ signin/social/ │ │
│ │ google │ │
│ ├────────────────────►│ │
│ │ │ OAuth redirect │
│ │ ├───────────────────►│
│◄───────────────────┴─────────────────────┴────────────────────┤
│ Provider Login Page │
├──────────────────────────────────────────────────────────────►│
│ User authorizes │
│◄──────────────────────────────────────────────────────────────┤
│ │ │ │
│ Redirect to │ GET /api/auth/ │ │
│ callback │ callback/google │ │
├───────────────────►├────────────────────►│ │
│ │ │ Exchange code │
│ │ ├───────────────────►│
│ │ │◄───────────────────┤
│ │ │ Create session │
│ │ Set-Cookie │ │
│◄───────────────────┴─────────────────────┤ │
│ Logged in ✅ │ │ │
User Frontend Backend
│ │ │
│ Enter email │ │
├───────────────────►│ │
│ │ POST /api/auth/ │
│ │ magic-link/ │
│ │ send │
│ ├────────────────────►│
│ │ │ Generate token
│ │ │ Send email
│ │ 200 OK │
│◄───────────────────┴─────────────────────┤
│ │
│ Click link in email │
├─────────────────────────────────────────►│
│ Verify token │
│ Create session │
│ Set-Cookie + redirect │
│◄─────────────────────────────────────────┤
│ Logged in ✅ │
- Created using Better Auth React
- Configured with
baseURL: window.location.origin - Uses Vite proxy in development (
/api/*→ backend) - Handles OAuth redirects and session management
- Centralized auth hook for all methods
- Methods:
loginWithGoogle,loginWithTwitter,logout - State:
user,session,isLoading
- Hono app mounted at
/api/auth/** - Routes handled automatically by Better Auth:
/api/auth/sign-up/email- Email sign up/api/auth/sign-in/email- Email sign in/api/auth/signin/social/google- Google OAuth/api/auth/callback/google- OAuth callback/api/auth/get-session- Get session/api/auth/sign-out- Logout/api/auth/magic-link/send- Send magic link/api/auth/email-otp/send- Send OTP
createAuth(config)— portable factory function- Accepts any Better Auth-compatible database
- Configures email/password, OAuth, magic link, email OTP
- Conditionally enables OAuth providers based on env vars
- Raw
fetchto Resend API (no SDK — works everywhere) - Functions:
sendEmail,sendOTP,sendMagicLinkEmail - Logs warning in dev when Resend is not configured
{
httpOnly: true, // Not accessible via JavaScript
secure: true, // HTTPS only in production
sameSite: 'lax', // CSRF protection
}cors({
origin: trustedOrigins, // Whitelist specific origins
credentials: true, // Allow cookies
})- Cloudflare: Use WAF Rate Limiting Rules (edge-level)
- Node.js: Add Hono rate limiter middleware
- scrypt hashing (OWASP recommended)
- Min 8 chars, max 128 chars
- Email verification required
- User authenticates (email, OAuth, magic link, OTP)
- Backend creates record in
sessiontable - Backend generates random session token
- Token stored in HTTP-only cookie
- Cookie sent with all requests via
credentials: "include"
- Browser sends cookie automatically
- Backend extracts token from cookie
- Query database for session
- Check expiration date
- Return user data if valid
Vite proxy forwards /api/* to backend:
// vite.config.ts
proxy: {
'/api': {
target: 'http://localhost:8787', // or :4200 for Node.js
changeOrigin: true,
}
}Frontend and backend on same domain via Cloudflare routing — no proxy needed.
Reverse proxy (Nginx, Caddy) handles routing:
location /api/ {
proxy_pass http://backend:4200/api/;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}See DEPLOYMENT.md for detailed deployment guides.
Key points:
- Use HTTPS for secure cookies
- Set strong
BETTER_AUTH_SECRET(min 32 chars) - Configure CORS with exact origins (no wildcards)
- Set up monitoring (health check at
/health)