Skip to main content

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