Adding authentication
This guide shows how to wire better-auth into either the Express or Hono example apps. The pattern works identically in your own project.
Install
pnpm add better-auth
better-auth needs a database adapter. See the better-auth docs for the full list. The snippets below omit the adapter config for brevity.
Express
src/auth.ts
import { betterAuth } from 'better-auth'
export const auth = betterAuth({
// database: ...,
emailAndPassword: { enabled: true },
})
src/index.ts (additions)
import { toNodeHandler } from 'better-auth/node'
import { auth } from './auth.js'
// Mount the auth routes before your app routes
app.all('/api/auth/*', toNodeHandler(auth))
src/middleware/requireAuth.ts
import type { RequestHandler } from 'express'
import { auth } from '../auth.js'
export const requireAuth: RequestHandler = async (req, res, next) => {
const session = await auth.api.getSession({ headers: req.headers as Headers })
if (!session) return void res.status(401).json({ success: false, error: 'Unauthorized' })
// ponytail: attach to locals so downstream handlers stay typed
res.locals.user = session.user
next()
}
Apply it to any route you want to protect:
import { requireAuth } from './middleware/requireAuth.js'
app.use('/items', requireAuth, itemsRouter)
Hono
src/auth.ts
import { betterAuth } from 'better-auth'
export const auth = betterAuth({
// database: ...,
emailAndPassword: { enabled: true },
})
src/index.ts (additions)
import { auth } from './auth.js'
// Mount the auth routes before your app routes
app.on(['GET', 'POST'], '/api/auth/*splat', (c) => auth.handler(c.req.raw))
src/middleware/requireAuth.ts
import type { MiddlewareHandler } from 'hono'
import { auth } from '../auth.js'
export const requireAuth: MiddlewareHandler = async (c, next) => {
const session = await auth.api.getSession({ headers: c.req.raw.headers })
if (!session) return c.json({ success: false, error: 'Unauthorized' }, 401)
c.set('user', session.user)
await next()
}
Apply it per-route or as a group middleware:
import { requireAuth } from './middleware/requireAuth.js'
app.use('/items/*', requireAuth)
Auth endpoints
Once mounted, better-auth exposes standard endpoints under /api/auth:
# Sign up
curl -X POST http://localhost:3001/api/auth/sign-up/email \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"secret","name":"You"}'
# Sign in
curl -X POST http://localhost:3001/api/auth/sign-in/email \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"secret"}'
The sign-in response includes a set-cookie header. Pass that cookie on subsequent requests to access protected routes.
Further reading
- better-auth installation
- better-auth adapters
- better-auth plugins (OAuth, magic link, 2FA, etc.)