Better Auth Integration
evlog/better-auth turns anonymous wide events into identified ones. Every request automatically includes who made it — no manual log.set({ user }) needed.
Prerequisites
Use Better Auth as a direct dependency in your app. evlog does not bundle Better Auth. The integration is tested against Better Auth >=1.6.9 (same major as the playground).
pnpm add better-auth
bun add better-auth
yarn add better-auth
npm install better-auth
Add Better Auth user identification
Quick Start
One middleware, all requests identified:
import { createAuthMiddleware } from 'evlog/better-auth'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
export default defineEventHandler(async (event) => {
if (!event.context.log) return
await identify(event.context.log, event.headers, event.path)
})
import { withEvlog, useLogger } from '@/lib/evlog'
import { createAuthMiddleware } from 'evlog/better-auth'
import { auth } from '@/lib/auth'
const identify = createAuthMiddleware(auth)
export const POST = withEvlog(async (request: Request) => {
const log = useLogger()
await identify(log, request.headers)
log.set({ action: 'checkout' })
return Response.json({ success: true })
})
import { createAuthMiddleware } from 'evlog/better-auth'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
app.use(async (req, res, next) => {
await identify(req.log, req.headers, req.path)
next()
})
import { createAuthMiddleware } from 'evlog/better-auth'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
app.use(async (c, next) => {
await identify(c.get('log'), c.req.raw.headers, c.req.path)
await next()
})
import { createAuthMiddleware } from 'evlog/better-auth'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
app.addHook('onRequest', async (request) => {
await identify(request.log, request.headers, request.url)
})
import { createAuthMiddleware } from 'evlog/better-auth'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
app.derive(async ({ log, request }) => {
await identify(log, request.headers, new URL(request.url).pathname)
return {}
})
import { createAuthMiddleware } from 'evlog/better-auth'
import { useLogger } from 'evlog/nestjs'
const identify = createAuthMiddleware(auth, {
exclude: ['/api/auth/**'],
})
@Injectable()
export class AuthIdentifyMiddleware implements NestMiddleware {
async use(req: Request, res: Response, next: NextFunction) {
await identify(useLogger(), req.headers, req.path)
next()
}
}
import { identifyUser } from 'evlog/better-auth'
import { createLogger } from 'evlog'
const log = createLogger()
const session = await auth.api.getSession({ headers })
if (session) identifyUser(log, session)
log.emit()
Your wide event now includes the user:
{
"level": "info",
"method": "POST",
"path": "/api/checkout",
"status": 200,
"duration": "120ms",
"requestId": "a5669202-7765-4f59-b6f0-b9f40ce71599",
"cart": { "items": 3, "total": 9999 }
}
{
"level": "info",
"method": "POST",
"path": "/api/checkout",
"status": 200,
"duration": "120ms",
"requestId": "a5669202-7765-4f59-b6f0-b9f40ce71599",
"userId": "QBX9tPjJQExWawAbNll75",
"user": {
"id": "QBX9tPjJQExWawAbNll75",
"name": "Hugo Richard",
"email": "hugo@example.com",
"emailVerified": true,
"createdAt": "2024-01-15T10:00:00.000Z"
},
"session": {
"id": "Xhmh6TxKJQrVKFX0Y0II",
"expiresAt": "2024-01-22T10:00:00.000Z",
"ipAddress": "192.168.1.42",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"createdAt": "2024-01-15T10:00:00.000Z"
},
"auth": {
"resolvedIn": 12,
"identified": true
},
"cart": { "items": 3, "total": 9999 }
}
How It Works
- middleware
route check · skip auth/**
- getSession(headers)
reads cookie · 12ms
db read · 0ms - identifyUser(log, session)
safe-fields whitelist
- emit wide event
all fields drained
The integration resolves the Better Auth session from request cookies, extracts a safe whitelist of user and session fields, sets them on the logger, then fires the onIdentify (or onAnonymous) hook. Auth routes are skipped by default. Resolution timing is captured on auth.resolvedIn, so you can chart auth latency alongside the rest of the wide event.
Where to next
Identify User
Middleware
include/exclude, react to identification with lifecycle hooks, and tune behaviour per app.Public API
| Export | Description |
|---|---|
identifyUser(log, session) | Core helper — extracts safe fields from a session and sets them on the logger. Returns true if identified. |
createAuthMiddleware(auth) | Returns an async (log, headers, path?) => Promise<boolean> function with route filtering, timing, and hooks. |
createAuthIdentifier(auth) | Nitro request hook factory for standalone Nitro apps. See Performance. |
maskEmail(email) | Mask an email: hugo@example.com → h***@example.com. |
Telemetry
Add tool execution timing and total wall time with createEvlogIntegration. Compose with other middleware like supermemory or guardrails.
Identify User
The core building block — extract safe user fields, mask emails, and capture plugin data (organizations, roles, 2FA) from a Better Auth session.