> ## Documentation Index
> Fetch the complete documentation index at: https://chatbase.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# User Identity

> How to identify users with JWT tokens and manage device-level identity in the Chatbase Android SDK.

## Overview

The SDK supports two layers of identity:

| Layer             | How It Works                              | Scope                              |
| ----------------- | ----------------------------------------- | ---------------------------------- |
| **Device ID**     | Automatic — generated on first use        | Conversations scoped to the device |
| **User Identity** | Opt-in — set a JWT token via `identify()` | Conversations scoped to the user   |

The SDK works anonymously out of the box. Call `identify()` to associate conversations with a specific user.

## Device ID

Every SDK instance has a stable device ID, generated automatically on creation:

```kotlin theme={null}
val deviceId: String
```

```kotlin theme={null}
val client = Chatbase.create(context, "YOUR_AGENT_ID")
println(client.deviceId) // "a1b2c3d4-e5f6-..."
```

<Note>
  The device ID uses Android's `Settings.Secure.ANDROID_ID` when available. On emulators or when restricted, it falls back to a UUID persisted in SharedPreferences (`chatbase_sdk_prefs`). The ID remains stable across app launches.
</Note>

## identify

`interface ChatbaseClient` — **Package:** `com.chatbase.sdk`

```kotlin theme={null}
suspend fun identify(token: String)
```

Verify a JWT token with the Chatbase server and identify the current user. Subsequent requests are associated with this user. `identify()` is equivalent to [`verify()`](#verify) — it verifies the token server-side and triggers the anonymous-conversation merge.

<ParamField body="token" type="String" required>
  A JWT generated by your backend and signed with your agent's identity verification secret. The payload must include a `user_id` (or `sub`) claim.
</ParamField>

<Steps>
  <Step title="Generate a JWT on your backend">
    Create a signed JWT token on your server containing the user ID in its payload.
  </Step>

  <Step title="Pass the token to the SDK">
    ```kotlin theme={null}
    client.identify(jwtToken)
    ```

    Conversations are now scoped to this user.
  </Step>

  <Step title="Check identity status">
    ```kotlin theme={null}
    println(client.isIdentified)   // true
    println(client.currentUserId)  // "user_123" (confirmed by the server during verification)
    ```
  </Step>
</Steps>

## Identity Properties

```kotlin theme={null}
val deviceId: String
```

Auto-generated device ID. Always available.

```kotlin theme={null}
val isIdentified: Boolean
```

`true` if a JWT token has been set via `identify()`.

```kotlin theme={null}
val currentUserId: String?
```

User ID confirmed by the server when the token was verified. `null` if not identified.

## verify

```kotlin theme={null}
suspend fun verify(token: String)
```

Verify a JWT token with the Chatbase server. On success, the server also merges any conversations created anonymously (with the device ID) into the verified user's account. `identify()` is an alias for this method.

<ParamField body="token" type="String" required>
  The JWT token to verify.
</ParamField>

```kotlin theme={null}
try {
    client.verify(jwtToken)
    println("Token is valid")
} catch (e: ApiException) {
    println("Token verification failed: ${e.errorMessage}")
}
```

<Info>
  When `verify()` succeeds, the server automatically merges previously anonymous (device-scoped) conversations into the verified user's account. Conversations started before identification are preserved and accessible under the user's identity.

  The merge runs asynchronously on the server — a `listConversations()` call issued immediately after `verify()` returns may not reflect it yet.
</Info>

## How Identity Affects Conversations

<Info>
  When identified, conversations are scoped to the user — `listConversations()` returns only that user's conversations. Without identity, conversations are scoped to the device.
</Info>

## logout

```kotlin theme={null}
fun logout()
```

Clear the JWT token and return to anonymous (device-scoped) mode. Also clears the current conversation ID so the next message starts a fresh anonymous conversation.

```kotlin theme={null}
client.logout()

println(client.isIdentified)          // false
println(client.currentUserId)         // null
println(client.currentConversationId) // null
println(client.deviceId)              // still available — unchanged
```

<Note>
  `identify()` and `verify()` are equivalent — both verify the token with the server and trigger the merge of prior anonymous (device-scoped) conversations into the user's account. You never need to call both.
</Note>

## Related

<CardGroup cols={2}>
  <Card title="Conversations & History" icon="messages" href="/docs/android-sdk/conversations">
    List conversations and load message history
  </Card>

  <Card title="Overview" icon="book-open" href="/docs/android-sdk/overview">
    SDK setup and configuration
  </Card>
</CardGroup>
