# Users and authentication

Anyone who interacts with your business through Live Chat is considered a **user**.

By default, Live Chat users are **unauthenticated** and have limited access to features and chat history. You can **authenticate** users by providing a unique identifier, such as an email address or phone number.

Authenticated users gain the following benefits:

- Persistent chat history
- Unique user identifier
- Access to chat history across multiple devices

Note
Chat history retention is subject to your account’s **Data retention** settings.

Each user is automatically tracked in [People](https://www.infobip.com/docs/people), which distinguishes between two user types: [*Leads* and *Customers*](https://www.infobip.com/docs/people/get-started#person-profile)

All unauthenticated users are assigned a *Lead* profile and once authenticated, they are automatically promoted to a *Customer*.

You can [configure your widget](https://www.infobip.com/docs/live-chat/widget-customization#installation-and-security-settings) to retain authenticated users as *Leads*.

## User authentication

You can **authenticate users** before they start a chat session **or** after they have begun chatting. If you authenticate a user who already has an existing chat history, the authenticated user will inherit that chat history.

When you authenticate a user for the **first time**, Live Chat automatically creates a new profile with the provided unique identifier, if a Person profile with that identifier does not already exist in [People](https://www.infobip.com/docs/people).

Authentication in Live Chat is achieved differently depending on whether you are authenticating a user on a website or in a mobile app.

## Web authentication

Web user authentication is managed via a **personalization token**, specifically, a [JSON Web Token (JWT)](https://jwt.io/) signed with your widget's secret key.

Note
As long as the token is correctly signed, Live Chat fully trusts that any data encoded within it is correct and was provided by you. Infobip does not take responsibility for any incorrect data that might, for example, result in users viewing another user’s chat history.

Important
Anyone with access to a JWT can read its contents. **Do not include confidential information, such as a password, in the token payload.**

As an integrator, you are responsible for generating the personalization token and providing it to the Live Chat widget.

To authenticate users, complete the following steps:

1. Obtain your widget's **secret key**.
2. Get the **unique identifier** of the user.
3. Generate the **personalization token**.
4. Submit the personalization token to the widget.

### Obtain your widget's secret key [#obtain-your-widgets-secret-key-web-authentication]

Each Live Chat widget can have one or more secret keys, which are used to sign personalization tokens.

To obtain a secret key:

1. Go to your widget's configuration page.
2. Navigate to the [Installation and Security](https://www.infobip.com/docs/live-chat/widget-customization#installation-and-security-settings) section → **Generate secret keys**.

Example of a key structure:

```json
{
  "id": "43f7a6d6-f064-4a6b-8890-fff70b1363ca",
  "key": "0wQGQwukZLkJNShlHS0Nm3SCiIwrWNfm7NEPOhukJhM="
}
```

- `id:` The unique identifier for your secret key. This value is included in the JWT's `ski` field.
- `key:` The secret value encoded in Base64, used to sign the JWT. Treat this key as confidential and handle it with the same care as a password.

You can remove a secret key at any time via the configuration interface.

### Obtain the unique identifier of your user [#obtain-the-unique-identifier-of-your-user-web-authentication]

To distinguish each user, you will need to supply a **unique identifier**. Live Chat supports three types of identifiers:

- **Email** - The user's email address
- **MSISDN** - The user's phone number, in MSISDN format
- **External ID** - Any string ID from your system that is unique per user

Note
If a user’s profile contains multiple identifiers, **any** of them can be used for authentication.

### Generate the personalization token [#generate-the-personalization-token-web-authentication]

Note
If you are not familiar with JSON Web Tokens (JWT), we **strongly recommend** reviewing their structure and creation process before proceeding.

To generate a personalization token, you must implement a JWT generator. The generated token must:

- Follow the structure defined in the **JWT payload structure** section
- Be signed with **the secret key obtained in the first step**
- Be **Base64 encoded**

Once the token is generated and encoded, supply it to the front end where Live Chat is embedded.

Tokens can **only** be used to authenticate a user **once**. You must generate a new token for each authentication attempt. Live Chat will maintain the authenticated session until you explicitly de-authenticate the user.

You can find JWT generator examples in the [Token generator examples](https://www.infobip.com/docs/live-chat/users-and-authentication#token-generator-examples) section.

#### JWT payload structure

| Field  | Required | Description |
|--------|:--------:|-------------|
| `alg`  | Yes      | *(Header value)* Encryption algorithm. Supported value: `HS256` |
| `typ`  | Yes      | *(Header value)* Type of the token. Supported value: `JWT` |
| `iat`  | Yes      | Issued at: [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) **in seconds** when the token is created. |
| `iss`  | Yes      | Issuer: your widget's ID. |
| `jti`  | Yes      | JWT ID: **must be unique** for each token. Any string, max 50 characters. |
| `ski`  | Yes      | Secret key ID: the **ID** (not the value) of the secret key you're using to sign the token. |
| `stp`  | Yes      | Subject type: type of identifier in `sub`. <br/>Allowed values:<br/>• `email`: standardized email format.<br/>• `msisdn`: phone number in MSISDN format.<br/>• `externalPersonId`: any string user identifier unique to your system, max 100 characters. |
| `sub`  | Yes      | Subject: value of the unique identifier, matching the type in `stp`. |
| `exp`  | No       | Expiration: [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) when the token expires **in seconds**. If not set, defaults to `iat + 15 seconds`.<br/>**Values less than** `iat + 15 seconds` **are not recommended**. |
| `sid`  | No       | Session ID: your unique user session identifier, used for [Session Invalidation API](https://www.infobip.com/docs/api/channels/live-chat/invalidate-customer-session). Max 50 characters. |

#### Example decoded token

```json
{
  "alg": "HS256",
  "typ": "JWT"
}.
{
  "iat": 1748599897,
  "iss": "da73dfca-7e33-43de-9e97-ece90aaada22",
  "jti": "c0625f5a-676c-4dcc-883d-eea8f06f4ae5",
  "ski": "43f7a6d6-f064-4a6b-8890-fff70b1363ca",
  "stp": "email",
  "sub": "john.doe@infobip.com",
  "exp": 1748599912,
  "sid": "8b52e759-5955-49d9-bb44-bc1b1ca22745"
}.
e4OIOAxyyjLNOk2TglcOmx4tpstrc4rBzYL-_gU1_I0
```

#### Example encoded token

`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NDg1OTk4OTcsImlzcyI6ImRhNzNkZmNhLTdlMzMtNDNkZS05ZTk3LWVjZTkwYWFhZGEyMiIsImp0aSI6ImMwNjI1ZjVhLTY3NmMtNGRjYy04ODNkLWVlYThmMDZmNGFlNSIsInNraSI6IjQzZjdhNmQ2LWYwNjQtNGE2Yi04ODkwLWZmZjcwYjEzNjNjYSIsInN0cCI6ImVtYWlsIiwic3ViIjoiam9obi5kb2VAaW5mb2JpcC5jb20iLCJleHAiOjE3NDg1OTk5MTIsInNpZCI6IjhiNTJlNzU5LTU5NTUtNDlkOS1iYjQ0LWJjMWIxY2EyMjc0NSJ9.e4OIOAxyyjLNOk2TglcOmx4tpstrc4rBzYL-_gU1_I0`

### Submit the personalization token to the widget [#submit-the-personalization-token-web-authentication]

Once you generate your token, use the SDK's [**Auth**](https://www.infobip.com/docs/live-chat/javascript-sdk-in-live-chat#auth) command to submit it to your widget. **Make sure to provide the token in its Base64 encoded form**.

After you successfully submit the token to the widget, the user will be authenticated.

## Mobile app authentication

For mobile app installations, Live Chat uses the Mobile SDK ([Android](https://github.com/infobip/mobile-messaging-sdk-android/wiki), [iOS](https://github.com/infobip/mobile-messaging-sdk-ios/wiki)) to manage users in **People**.

To learn more about how the Mobile SDK manages your users, see the **Users and installations** section in the [Android](https://github.com/infobip/mobile-messaging-sdk-android/wiki/Users-and-installations) or [iOS](https://github.com/infobip/mobile-messaging-sdk-ios/wiki/Users-and-installations) documentation.

Because **Push Registration ID** (Infobip's unique identifier for the user's device) also uniquely identifies anonymous users, **all mobile users with a profile in People retain their chat history indefinitely**, regardless of their _Lead_ or _Customer_ status.

### Additional security [#additional-security-mobile-app-authentication]

For enhanced security, you can require a personalization token during mobile app authentication. The token must be generated in the same way as for web authentication, then provided to the Mobile SDK.

For detailed instructions on how to provide the token to the Mobile SDK, refer to the [Android](https://github.com/infobip/mobile-messaging-sdk-android/wiki/In%E2%80%90app-chat#authenticated-chat) or [iOS](https://github.com/infobip/mobile-messaging-sdk-ios/wiki/In%E2%80%90app-chat#authenticated-chat) documentation.

When authenticating on mobile using a personalization token, Live Chat **does not** automatically add the unique identifier to the user’s People profile or create a new profile. The unique identifier provided in the token must already exist in the user’s profile.

You can ensure this by one of the following methods:

- **Update the user profile manually**
- **Use the Personalize function in the Mobile SDK**
- **Call the Personalize push instance REST API**

To enable additional security for your mobile users:

1. Go to your widget's configuration page.
2. Navigate to the [Installation and Security](https://www.infobip.com/docs/live-chat/widget-customization#installation-and-security-settings) section.
3. Turn on **Mobile app customer authentication**.

#### Best practice

When authenticating users on mobile, it is recommended to use a **longer TTL** (time-to-live, set in the token’s `exp` field). The personalization token supports both initial authentication and automatic re-authentication if certain errors occur. Setting a longer TTL helps keep users authenticated and reduces interruptions during the chat experience.

## De-authenticating users

Typically, you authenticate users with Live Chat when they authenticate or log in to your platform. For a seamless experience and better security, it is recommended to de-authenticate users when they log out.

You can de-authenticate users by:

- **Web** - Use the [**Log out**](https://www.infobip.com/docs/live-chat/javascript-sdk-in-live-chat#log-out) Live Chat SDK command.
- **Mobile app** - Use the **Depersonalize** function in Mobile SDK ([Android](https://github.com/infobip/mobile-messaging-sdk-android/wiki/Users-and-installations#depersonalization), [iOS](https://github.com/infobip/mobile-messaging-sdk-ios/wiki/Users-and-installations#depersonalization)).
- **Web and mobile app** - Call the [Invalidate session API](https://www.infobip.com/docs/api/channels/live-chat/invalidate-customer-session). Note that to use this API, you must include a **Session Identifier** (`sid`) in the personalization token.

## Token generator examples

Note
Do not forget to decode your secret key from Base64 before using it for the signature.

### Node.js [#node-js-token-generator-examples]

```javascript
const jwt = require('jsonwebtoken');

const securityKey = JSON.parse(
'{"id":"43f7a6d6-f064-4a6b-8890-fff70b1363ca","key":"0wQGQwukZLkJNShlHS0Nm3SCiIwrWNfm7NEPOhukJhM="}'
);

const now = Math.floor(Date.now() / 1000);

const payload = {
  iat: now,
  iss: 'da73dfca-7e33-43de-9e97-ece90aaada22',
  jti: 'c0625f5a-676c-4dcc-883d-eea8f06f4ae5',
  ski: securityKey.id,
  stp: 'email',
  sub: 'john.doe@infobip.com',
  exp: now + 15,
  sid: '8b52e759-5955-49d9-bb44-bc1b1ca22745'
};

const token = jwt.sign(payload, Buffer.from(securityKey.key, 'base64'));

console.log(token);
```

### Java [#java-token-generator-examples]

```java
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Component
class PersonalisationTokenGenerator {
    public ResponseEntity<string> generate(String widgetId, String securityKey) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            SecurityKeyHMAC secret = mapper.readValue(securityKey, SecurityKeyHMAC.class);

            MACSigner signer = new MACSigner(Base64.getDecoder().decode(secret.getKey()));

            long now = Instant.now().getEpochSecond();

            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                    .issueTime(new Date(now * 1000))
                    .issuer(widgetId)
                    .jwtID("c0625f5a-676c-4dcc-883d-eea8f06f4ae5")
                    .claim("ski", secret.getId())
                    .claim("stp", "email")
                    .subject("john.doe@infobip.com")
                    .expirationTime(new Date((now + 15) * 1000))
                    .claim("sid", "8b52e759-5955-49d9-bb44-bc1b1ca22745")
                    .build();

            SignedJWT token = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
            token.sign(signer);

            return ResponseEntity.ok(token.serialize());
        } catch (Exception ex) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}

class SecurityKeyHMAC {
    private String id;
    private String key;

    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getKey() { return key; }
    public void setKey(String key) { this.key = key; }
}
```

### Kotlin [#kotlin-token-generator-examples]

```kotlin
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.nimbusds.jose.JWSAlgorithm
import com.nimbusds.jose.JWSHeader
import com.nimbusds.jose.crypto.MACSigner
import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.jwt.SignedJWT
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Component
import java.time.Instant
import java.util.*

@Component
class PersonalisationTokenGenerator {
    fun authorize(widgetId: String, securityKey: String): ResponseEntity<string> {
        return try {
            val mapper = jacksonObjectMapper()
            val secret = mapper.readValue(securityKey, SecurityKeyHMAC::class.java)

            val signer = MACSigner(Base64.getDecoder().decode(secret.key))
            val now = Instant.now().epochSecond

            val claimsSet = JWTClaimsSet.Builder()
                .issueTime(Date(now * 1000))
                .issuer(widgetId)
                .jwtID("c0625f5a-676c-4dcc-883d-eea8f06f4ae5")
                .claim("ski", secret.id)
                .claim("stp", "email")
                .subject("john.doe@infobip.com")
                .expirationTime(Date((now + 15) * 1000))
                .claim("sid", "8b52e759-5955-49d9-bb44-bc1b1ca22745")
                .build()

            val token = SignedJWT(JWSHeader(JWSAlgorithm.HS256), claimsSet)
            token.sign(signer)

            ResponseEntity.ok(token.serialize())
        } catch (ex: Exception) {
            ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()
        }
    }
}

data class SecurityKeyHMAC(val id: String, val key: String)
```

### Swift [#swift-token-generator-examples]

```swift
import SwiftJWT

struct JWTClaims: Claims {
    let iat: Date
    let iss: String
    let jti: String
    let ski: String
    let stp: String
    let sub: String
    let exp: Date
    let sid: String
}

let now = Date()
let claims = JWTClaims(
    iat: now,
    iss: "da73dfca-7e33-43de-9e97-ece90aaada22",
    jti: "c0625f5a-676c-4dcc-883d-eea8f06f4ae5",
    ski: "43f7a6d6-f064-4a6b-8890-fff70b1363ca",
    stp: "email",
    sub: "john.doe@infobip.com",
    exp: now.addingTimeInterval(15),
    sid: "8b52e759-5955-49d9-bb44-bc1b1ca22745"
)

let jwt = JWT(header: Header(), claims: claims)
let secret = Data(base64Encoded: "0wQGQwukZLkJNShlHS0Nm3SCiIwrWNfm7NEPOhukJhM=")!

let signer = JWTSigner.hs256(key: secret)
let signedJWT = try? jwt.sign(using: signer)
```

### PHP [#php-token-generator-examples]

```php
use \Firebase\JWT\JWT;

$timestamp = time();
$securityKey = json_decode('{"id":"43f7a6d6-f064-4a6b-8890-fff70b1363ca","key":"0wQGQwukZLkJNShlHS0Nm3SCiIwrWNfm7NEPOhukJhM="}');

$payload = [
    'iat' => $timestamp,
    'iss' => 'da73dfca-7e33-43de-9e97-ece90aaada22',
    'jti' => 'c0625f5a-676c-4dcc-883d-eea8f06f4ae5',
    'ski' => $securityKey->id,
    'stp' => 'email',
    'sub' => 'john.doe@infobip.com',
    'exp' => $timestamp + 15,
    'sid' => '8b52e759-5955-49d9-bb44-bc1b1ca22745'
];

$token = JWT::encode($payload, base64_decode($securityKey->key), 'HS256');
```