---
title: "Better Auth Integration"
description: "Identify the user on authenticated requests, so each wide event carries who made it without a manual log.set call."
canonical_url: "https://www.evlog.dev/use-cases/better-auth/overview"
---
# Better Auth Integration

> Identify the user on authenticated requests, so each wide event carries who made it without a manual log.set call.

`evlog/better-auth` turns anonymous wide events into identified ones. Every request automatically includes who made it, with no manual `log.set({ user })` needed.

## Before you wire it

Use [Better Auth](https://better-auth.com/) 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](https://github.com/evloghq/evlog/tree/main/apps/playground)).

<code-group>

```bash [pnpm]
pnpm add better-auth
```

```bash [bun]
bun add better-auth
```

```bash [yarn]
yarn add better-auth
```

```bash [npm]
npm install better-auth
```

</code-group>

<prompt :actions="["copy","cursor","claude"]" description="Add Better Auth user identification" icon="i-simple-icons-betterauth">

Add Better Auth user identification to my app with evlog.

- Import createAuthMiddleware from 'evlog/better-auth'
- Call createAuthMiddleware(auth) to get an identify function
- Call identify(log, headers, path) in your middleware/hook to auto-identify users on every request
- Safe by default. Only extracts whitelisted fields, and never logs passwords or tokens
- Supports include/exclude route patterns, lifecycle hooks, and Better Auth plugin fields
- Works with all frameworks: Nuxt, Next.js, Express, Hono, Fastify, NestJS, Elysia, standalone

Docs: [https://www.evlog.dev/use-cases/better-auth/overview](https://www.evlog.dev/use-cases/better-auth/overview)
Adapters: [https://www.evlog.dev/integrate/adapters/overview](https://www.evlog.dev/integrate/adapters/overview)

</prompt>

## Quick Start

One middleware, all requests identified:

<framework-tabs>

```typescript [Nuxt]server/middleware/auth-identify.ts
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)
})
```

```typescript [Next.js]app/api/checkout/route.ts
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 })
})
```

```typescript [Express]src/index.ts
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()
})
```

```typescript [Hono]src/index.ts
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()
})
```

```typescript [Fastify]src/index.ts
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)
})
```

```typescript [Elysia]src/index.ts
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 {}
})
```

```typescript [NestJS]src/auth-identify.middleware.ts
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()
  }
}
```

```typescript [Standalone]scripts/sync-job.ts
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()
```

</framework-tabs>

Your wide event now includes the user:

<code-group>

```json [Before — anonymous]
{
  "level": "info",
  "method": "POST",
  "path": "/api/checkout",
  "status": 200,
  "duration": "120ms",
  "requestId": "a5669202-7765-4f59-b6f0-b9f40ce71599",
  "cart": { "items": 3, "total": 9999 }
}
```

```json [After — identified]
{
  "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 }
}
```

</code-group>

## How the session reaches the event

<better-auth-identify>



</better-auth-identify>

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

<card-group>
<card icon="i-lucide-user-check" title="Identify User" to="https://www.evlog.dev/use-cases/better-auth/identify-user">

The core building block: extract safe fields, mask emails, capture plugin data (organizations, roles, 2FA).

</card>

<card icon="i-lucide-shield" title="Middleware" to="https://www.evlog.dev/use-cases/better-auth/middleware">

Filter routes with `include`/`exclude`, react to identification with lifecycle hooks, and tune behaviour per app.

</card>

<card icon="i-lucide-monitor" title="Client Sync" to="https://www.evlog.dev/use-cases/better-auth/client-sync">

Mirror the user identity into client-side logs with `setIdentity` and the Better Auth client.

</card>

<card icon="i-lucide-gauge" title="Performance" to="https://www.evlog.dev/use-cases/better-auth/performance">

Watch session resolution time, enable session caching, and combine with the AI SDK integration.

</card>
</card-group>

## What the package exports

<table>
<thead>
  <tr>
    <th>
      Export
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        identifyUser(log, session)
      </code>
    </td>
    
    <td>
      Core helper — extracts safe fields from a session and sets them on the logger. Returns <code>
        true
      </code>
      
       if identified.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        createAuthMiddleware(auth)
      </code>
    </td>
    
    <td>
      Returns an async <code>
        (log, headers, path?) => Promise<boolean>
      </code>
      
       function with route filtering, timing, and hooks.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        createAuthIdentifier(auth)
      </code>
    </td>
    
    <td>
      Nitro <code>
        request
      </code>
      
       hook factory for standalone Nitro apps. See <a href="https://www.evlog.dev/use-cases/better-auth/performance#standalone-nitro">
        Performance
      </a>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maskEmail(email)
      </code>
    </td>
    
    <td>
      Mask an email: <code>
        hugo@example.com
      </code>
      
       → <code>
        h***@example.com
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

---

- [Identify User](https://www.evlog.dev/use-cases/better-auth/identify-user)
- [Middleware](https://www.evlog.dev/use-cases/better-auth/middleware)
- [Client Sync](https://www.evlog.dev/use-cases/better-auth/client-sync)
- [Performance](https://www.evlog.dev/use-cases/better-auth/performance)


## Sitemap

See the full [sitemap](https://www.evlog.dev/sitemap.md) for all pages.
