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

# Mobile Authentication

> Authentication methods for AGO mobile API integration

This guide covers authentication methods for integrating AGO APIs in your mobile application.

## Base URL

```
https://yourtenant.api.example.com/api/sdk/v1
```

## Authentication Modes

<Note>
  AGO supports two authentication modes for mobile integration: **JWT Authentication** for users with accounts, and **Widget Authentication** for anonymous users or embedded chat widgets.
</Note>

***

## 1. JWT Authentication (Authenticated Mode)

For users with accounts, use JWT tokens alongside the widget authentication headers. The `Authorization` header is added to the standard widget headers:

```
X-User-Anon-Id: UNIQUE_DEVICE_ID
Origin: https://your-app-domain.com
Authorization: Bearer YOUR_JWT_TOKEN
```

<Note>
  When a JWT is sent, the `X-User-Anon-Id` header is optional: the user identity is taken from the token's `sub` claim.
</Note>

### When to Use JWT

* Users have registered accounts in your system
* You want full user identity and history
* Users log in through your existing authentication flow

### Obtaining a JWT Token

Your backend should generate JWT tokens after user authentication. The token must be signed with the secret configured in your AGO instance.

***

## 2. Widget Authentication (Anonymous Mode)

For anonymous users or embedded chat widgets, use widget authentication with the following headers:

```
X-User-Anon-Id: UNIQUE_DEVICE_ID
X-Widget-Email: user@example.com  (optional)
Origin: https://your-app-domain.com
```

### Header Reference

| Header           | Required | Description                                                                                                                                       |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-User-Anon-Id` | Yes      | A unique identifier for the device/session (e.g., UUID). Creates a persistent anonymous user. `X-Widget-Id` is the legacy name and still accepted |
| `X-Widget-Email` | No       | The user's real email for tracking purposes (stored separately from the anonymous account)                                                        |
| `Origin`         | Yes      | Your application's domain (must be in the allowed domains list)                                                                                   |

<Info>
  **How Widget Mode Works:**

  1. The system creates an anonymous user with email format: `unknown_ago@{user-id}.com`
  2. All conversations are tied to this anonymous user
  3. The same user ID should be used across sessions for conversation continuity
  4. The real email (if provided) is stored in `additional_info` for admin reference
</Info>

***

## Widget Mode Setup

<Warning>
  ### Prerequisites

  Before using widget mode in your mobile app:

  1. **Allow Your Domain**: Add your app's domain/origin to the allowed domains list
  2. **Persistent Storage**: Store the user ID persistently to maintain conversation continuity
</Warning>

### Security Considerations

* **User ID**: Must be unique per device/user and stored persistently
* **Domain Validation**: The Origin header must match allowed domains exactly
* **Anonymous Users**: System creates users with format `unknown_ago@{user-id}.com`
* **Real Email Tracking**: Optional X-Widget-Email is stored separately for admin reference

***

## Implementation Examples

### Swift (iOS) - JWT Mode

```swift theme={null}
class AgoChatSDK {
    let baseURL = "https://your-domain.example.com/api/sdk/v1"
    var authToken: String
    let widgetId: String
    let origin: String

    init(authToken: String, widgetId: String, origin: String) {
        self.authToken = authToken
        self.widgetId = widgetId
        self.origin = origin
    }

    func createRequest(for endpoint: String) -> URLRequest {
        let url = URL(string: "\(baseURL)/\(endpoint)")!
        var request = URLRequest(url: url)
        request.setValue(widgetId, forHTTPHeaderField: "X-User-Anon-Id")
        request.setValue(origin, forHTTPHeaderField: "Origin")
        request.setValue("Bearer \(authToken)", forHTTPHeaderField: "Authorization")
        return request
    }
}
```

### Swift (iOS) - Widget Mode

```swift theme={null}
class AgoChatWidgetSDK {
    let baseURL = "https://your-domain.example.com/api/sdk/v1"
    let widgetId: String  // Store persistently
    let origin: String
    var userEmail: String?  // Optional real email

    init(origin: String) {
        self.origin = origin

        // Generate or retrieve persistent widget ID
        if let savedId = UserDefaults.standard.string(forKey: "ago_widget_id") {
            self.widgetId = savedId
        } else {
            self.widgetId = UUID().uuidString
            UserDefaults.standard.set(self.widgetId, forKey: "ago_widget_id")
        }
    }

    func createRequest(for endpoint: String) -> URLRequest {
        let url = URL(string: "\(baseURL)/\(endpoint)")!
        var request = URLRequest(url: url)
        request.setValue(widgetId, forHTTPHeaderField: "X-User-Anon-Id")
        request.setValue(origin, forHTTPHeaderField: "Origin")
        if let email = userEmail {
            request.setValue(email, forHTTPHeaderField: "X-Widget-Email")
        }
        return request
    }
}
```

### Kotlin (Android) - JWT Mode

```kotlin theme={null}
class AgoChatSDK(
    private val authToken: String,
    private val widgetId: String,
    private val origin: String
) {
    private val baseURL = "https://your-domain.example.com/api/sdk/v1"

    fun createRequest(endpoint: String): Request.Builder {
        return Request.Builder()
            .url("$baseURL/$endpoint")
            .header("X-User-Anon-Id", widgetId)
            .header("Origin", origin)
            .header("Authorization", "Bearer $authToken")
    }
}
```

### Kotlin (Android) - Widget Mode

```kotlin theme={null}
class AgoChatWidgetSDK(
    private val origin: String,
    private val context: Context
) {
    private val baseURL = "https://your-domain.example.com/api/sdk/v1"
    private val widgetId: String
    var userEmail: String? = null

    init {
        // Generate or retrieve persistent widget ID
        val sharedPrefs = context.getSharedPreferences("ago_chat", Context.MODE_PRIVATE)
        widgetId = sharedPrefs.getString("widget_id", null) ?: UUID.randomUUID().toString().also {
            sharedPrefs.edit().putString("widget_id", it).apply()
        }
    }

    fun createRequest(endpoint: String): Request.Builder {
        val builder = Request.Builder()
            .url("$baseURL/$endpoint")
            .header("X-User-Anon-Id", widgetId)
            .header("Origin", origin)

        userEmail?.let { builder.header("X-Widget-Email", it) }
        return builder
    }
}
```

***

## Best Practices

<Tip>
  ### Authentication Mode Selection

  * Use JWT mode for registered users with accounts
  * Use Widget mode for anonymous users or embedded chat scenarios
  * Never mix authentication modes in the same session
</Tip>

<Tip>
  ### User ID Management

  * Generate UUID once per installation
  * Store persistently (UserDefaults/SharedPreferences)
  * Use same ID across app sessions for conversation continuity
  * Clear ID only on app uninstall or user logout
</Tip>

<Tip>
  ### Error Handling

  * Handle 401 errors (invalid or expired token)
  * Handle 403 errors (domain not in allowed list)
  * Implement token refresh for JWT mode
  * Show user-friendly error messages
</Tip>

***

## Related Documentation

* [Mobile Messaging API](./mobile-messaging) - Send and receive messages
* [Mobile Ticketing API](./mobile-ticketing) - Create support tickets
* [Mobile SDK Examples](./mobile-sdk) - Complete implementation examples
* [Widget Authentication](../security/widget-authentication) - Widget security details
