Better Auth

createAuthMiddleware

Framework-agnostic factory with route filtering, session timing, and lifecycle hooks. Call it once at startup and reuse across requests.

createAuthMiddleware wraps identifyUser with the things you need on every request: route filtering, session resolution timing, lifecycle hooks, and silent error handling. Call it once at startup, then use the returned function in your framework's middleware/hook system.

server/middleware/auth-identify.ts
import { createAuthMiddleware } from 'evlog/better-auth'

const identify = createAuthMiddleware(auth, {
  exclude: ['/api/auth/**', '/api/public/**'],
  include: ['/api/**'],
  maskEmail: true,
})

The function signature is (log, headers, path?) => Promise<boolean>. It resolves the session, calls identifyUser, captures timing into auth.resolvedIn, fires lifecycle hooks, and silently catches errors so session resolution never breaks a request.

Options

Inherits all identifyUser options, plus:

OptionTypeDefaultDescription
excludestring[]['/api/auth/**']Route patterns to skip (glob).
includestring[]undefinedIf set, only matching routes are resolved.
onIdentify(log, session) => voidundefinedCalled after successful identification.
onAnonymous(log) => voidundefinedCalled when no session is found.

Route Filtering

Skip Better Auth's own routes and any public endpoints to avoid wasted database queries:

const identify = createAuthMiddleware(auth, {
  exclude: [
    '/api/auth/**',     // Better Auth itself
    '/api/public/**',   // Public endpoints
    '/api/health',      // Health checks
  ],
})

For high-traffic apps, flip the model — only resolve sessions on routes that need them:

const identify = createAuthMiddleware(auth, {
  include: ['/api/dashboard/**', '/api/account/**'],
})

include and exclude use glob patterns (*, **). Provide both if you need granular control — exclude wins over include.

Lifecycle Hooks

Use onIdentify to react to user identification — for example, force-keep logs for premium users via tail sampling:

server/middleware/auth-identify.ts
const identify = createAuthMiddleware(auth, {
  onIdentify: (log, session) => {
    if (session.user.plan === 'enterprise') {
      log.set({ _forceKeep: true })
    }
  },
  onAnonymous: (log) => {
    log.set({ anonymous: true })
  },
})

Hooks fire after the session is resolved and identifyUser has set its fields. They run on every request that passes the include/exclude filter, so keep them fast and side-effect-free.

Common patterns for onIdentify:
  • Force-keep audit logs for admins or high-value plans.
  • Tag the request with feature flags or tenant info loaded from the session.
  • Increment a per-user counter for billing.

Error Handling

The middleware catches every error from getSession and logs nothing — your request keeps flowing whether the auth backend is up or down. The wide event still includes auth.resolvedIn and auth.identified: false so you can alert on session resolution health from your dashboards.