---
title: "identifyUser"
description: "The core building block — extract safe user fields, mask emails, and capture plugin data (organizations, roles, 2FA) from a Better Auth session."
canonical_url: "https://www.evlog.dev/use-cases/better-auth/identify-user"
---
# identifyUser

> The core building block — extract safe user fields, mask emails, and capture plugin data (organizations, roles, 2FA) from a Better Auth session.

`identifyUser` is the core building block. Take a `RequestLogger` and a Better Auth session, extract safe fields, and call `log.set()`. Returns `true` if the user was identified, `false` otherwise.

```typescript [server/api/checkout.post.ts]
import { identifyUser } from 'evlog/better-auth'

const session = await auth.api.getSession({ headers: event.headers })
if (session) {
  const identified = identifyUser(log, session)
  if (identified) {
    log.set({ subscription: 'premium' })
  }
}
```

<tip>

**Safe by default.** Only whitelisted fields are extracted, and passwords, tokens, and secrets are never written to the logger.

</tip>

## Options

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        maskEmail
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Mask emails as <code>
        h***@example.com
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Include session metadata (<code>
        session.id
      </code>
      
      , <code>
        session.expiresAt
      </code>
      
      , <code>
        session.ipAddress
      </code>
      
      , <code>
        session.userAgent
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fields
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        ['id', 'name', 'email', 'image', 'emailVerified', 'createdAt']
      </code>
    </td>
    
    <td>
      User fields to extract.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        extend
      </code>
    </td>
    
    <td>
      <code>
        (session) => Record<string, unknown>
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Add custom fields from Better Auth plugins (organizations, roles, etc.).
    </td>
  </tr>
</tbody>
</table>

```typescript [services/checkout.ts]
identifyUser(log, session, {
  maskEmail: true,
  fields: ['id', 'name'],
  session: false,
})
```

## Mask emails

Emails are PII. In environments where the audit/log trail might be reviewed by support or third parties, mask them:

```typescript
identifyUser(log, session, { maskEmail: true })
```

The `maskEmail` helper is also exported on its own:

```typescript
import { maskEmail } from 'evlog/better-auth'

maskEmail('hugo@example.com') // 'h***@example.com'
```

## Capture plugin fields

Better Auth ships with plugins (organizations, 2FA, roles, admin) that add fields to the session. Use `extend` to surface them on the wide event:

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

const identify = createAuthMiddleware(auth, {
  extend: (session) => ({
    organization: session.user.activeOrganization,
    role: session.user.role,
  }),
})
```

Wide event with plugin fields:

```json [Wide Event]
{
  "userId": "QBX9tPjJQExWawAbNll75",
  "user": { "id": "QBX9tPjJQExWawAbNll75", "name": "Hugo Richard" },
  "organization": { "id": "org_42", "name": "Acme" },
  "role": "admin"
}
```

<tip>

Keep `extend` deterministic, because it runs on every request. Avoid heavy computations or extra database calls inside it; query the data Better Auth already loaded into the session.

</tip>

## Fields that reach the event

<table>
<thead>
  <tr>
    <th>
      Field
    </th>
    
    <th>
      Source
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        userId
      </code>
    </td>
    
    <td>
      <code>
        session.user.id
      </code>
    </td>
    
    <td>
      Top-level user ID (used by PostHog adapter as <code>
        distinct_id
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.id
      </code>
    </td>
    
    <td>
      <code>
        session.user.id
      </code>
    </td>
    
    <td>
      User ID.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.name
      </code>
    </td>
    
    <td>
      <code>
        session.user.name
      </code>
    </td>
    
    <td>
      Display name.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.email
      </code>
    </td>
    
    <td>
      <code>
        session.user.email
      </code>
    </td>
    
    <td>
      Email (maskable with <code>
        maskEmail: true
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.image
      </code>
    </td>
    
    <td>
      <code>
        session.user.image
      </code>
    </td>
    
    <td>
      Avatar URL.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.emailVerified
      </code>
    </td>
    
    <td>
      <code>
        session.user.emailVerified
      </code>
    </td>
    
    <td>
      Email verification status.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        user.createdAt
      </code>
    </td>
    
    <td>
      <code>
        session.user.createdAt
      </code>
    </td>
    
    <td>
      Account creation date (ISO string).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session.id
      </code>
    </td>
    
    <td>
      <code>
        session.session.id
      </code>
    </td>
    
    <td>
      Session ID.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session.expiresAt
      </code>
    </td>
    
    <td>
      <code>
        session.session.expiresAt
      </code>
    </td>
    
    <td>
      Session expiry (ISO string).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session.ipAddress
      </code>
    </td>
    
    <td>
      <code>
        session.session.ipAddress
      </code>
    </td>
    
    <td>
      Client IP from the session.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session.userAgent
      </code>
    </td>
    
    <td>
      <code>
        session.session.userAgent
      </code>
    </td>
    
    <td>
      User agent string from the session.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        session.createdAt
      </code>
    </td>
    
    <td>
      <code>
        session.session.createdAt
      </code>
    </td>
    
    <td>
      Session creation date (ISO string).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        auth.resolvedIn
      </code>
    </td>
    
    <td>
      Measured
    </td>
    
    <td>
      Session resolution time in ms.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        auth.identified
      </code>
    </td>
    
    <td>
      Computed
    </td>
    
    <td>
      Whether the request was identified.
    </td>
  </tr>
</tbody>
</table>

---

- [Overview](https://www.evlog.dev/use-cases/better-auth/overview)
- [Middleware](https://www.evlog.dev/use-cases/better-auth/middleware)


## Sitemap

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