Live Chat
User types

User types

In this article, we will discuss the difference between Leads and Authenticated Customers using your Live Chat web widget.

Live Chat - customer authentication process

Leads

By default, all leads can see your website widget. You can change this by configuring and customizing who will see your live chat widget.

Leads will also be able to see their chat history once they have initiated a conversation. However, for security reasons, we have introduced the chat session timeout. (opens in a new tab)

Every lead session can be personalized with a personalization token. Once the widget session is signed with the personalization token, it becomes a trusted session with an authenticated customer.

The website backend application controls trusted sessions and can interrupt the session on any logic that the website backend application has. For example, when a customer logs out, the website’s backend application should terminate this trusted session.

Find out more on how to authenticate customers in the Customer Authentication Setup section.

Authenticated customers

Once you add the web widget to your website, by default, all leads and customers who initiate a conversation over that widget are flagged as leads.

However, you can configure the web widget to identify authenticated customers if they are logged in based on your website authentication logic.

Authenticated customers are customers who log in to your website. Authenticated customers can see their entire conversation history within the widget once they log in.

Conversations started by the anonymous visitor can be converted into a conversation with an authenticated user once this customer logs in to your website. Then the entire conversation will be stored as an authenticated customer chat session.

NOTE

Infobip does not authenticate your customers through Live Chat. Customer authentication is executed within your website’s backend application.

Here is a high-level overview of how you can enable authenticated customer chat sessions on your website:

  1. Generate a secret key from your widget configuration.
  2. Implement personalization token generator on your website backend application.
  3. Add Widget API auth method to your authenticated customers' chat session.
  4. Manage your authenticated customers logout.

Enable authenticated customers

This section explains how the Live Chat customer authentication process works.

To set up the customer authentication, follow the guide below:

Generate secret key

The secret key is a special encryption key used to generate the personalization token. For security reasons, we recommend you keep this secret key safe to avoid data leakage.

You can have as many secret keys as you need. Each secret key is unique for each widget and can be associated only with a specific widget ID.

To generate a secret key, navigate to the Channels and Numbers module located at the bottom left → Live Chat, select a widget to edit, then navigate to the Installation & Security section and click Generate New Key.

Here is what the secret key looks like once it is generated:

Live Chat - Generate secret key ID

Copy the key to your clipboard (here's an example):

{"id":3,"key":"7Q25YT4fKM7G+BO/7QyW9vdF/YC8zBN3w4HQPyKgk98="}
NOTE

Bear in mind that the secret key is Base64 string representation.

In-app authentication

In-app (mobile) authentication is achieved via the Identify Livechat Javascript SDK method which issues a Live Chat session key based on either Push registration ID or user data provided via JWT. This key is tied with a unique user registration, which is used to pair the user with their chat history, routing, etc.

There are two possible ways of issuing a session key that split identify into two similar flows, but there is a minor distinction between them – JWT flow searches for a person by identity inferred from the token (email/phone/external ID) whereas Push registration ID flow searches by Push registration ID only.

NOTE

Push registration ID is mandatory in both flows, whereas JWT is mandatory only in JWT flow. Push registration ID is required for the JWT flow since it performs a check to see whether the found person has this specific Push registration ID in its destinations. Once the widget is configured to authenticate the mobile via JWT, users cannot longer be verified only using the Push registration ID.

JWT authentication

JWT (JSON Web Token) is generated using the same process as for the web. The token's user information, specifically stp and sub, should match the individual who registered with the installation. In other words, make sure you provide the customer data you have personalized the app for, or the lead data if you have set it manually in the People module.

The following steps are required to implement this:

  • Configure the JWT generator
  • Turn on configuration in the widget to start using JWT in mobile authentication
  • Code it using the exact part of the library In‐app-chat (opens in a new tab)
NOTE

It is advised to use a longer TTL (time-to-live, or how long till the token expires – exp field in JWT) for JWT when authenticating mobile because this token is not only used when authenticating for the first time but also when an error happens - Live Chat uses the provided JWT to attempt to re-authenticate the user automatically.

By default, the authentication method is set to use the Push registration ID, so if you want to authenticate via the Push registration ID, you do not have to make any changes. In case you want to authenticate via JWT, you can turn it on via the Mobile app customer authentication switch under the Security and Installation section in the widget configuration:

Live Chat - Mobile authentication

Once turned on, confirmation of user data is sent through JWT that is offering guaranteed strong security and since JWTs are digitally signed, they cannot be modified by the client or intruder.

Each secret key contains the following information:

  • The date of creation
  • The time it was last used (the last time the widget had signed a conversation with this security key)

Personalization token generator

The personalization token is based on JSON Web Token (JWT) technology (opens in a new tab). Within your application backend, you need to implement the JWT personalization and sign in with the secret key you previously copied.

Infobip supports the HMAC encryption algorithm verification (default HS256), a worldwide popular encryption algorithm. This is a standardized snippet to generate a token with additional parameters.

ALERT

Personalization token can be used only once to sign in the customer authentication chat session. Authenticated chat session will be automatically maintained by Infobip web widget until you invalidate the session with the widget logout method or invalidate session API call (opens in a new tab).

To generate a token, you need the following:

  • Customer’s unique identifier (phone number, email or externalUserID)
  • Secret key (secret key ID)

Output from snippet:

  • ID – Personalization token ID
  • Personalization token

Here are the parameters to form a JWT payload with personalization parameters data from your backend:

ParameterMandatoryDescription
algyesEncryption algorithm. Supported value HS256
expoptionalToken expiration time. POSIX time format in SEC. The default value is 15 seconds. Personalization token is for single use only and its “short-lived” to keep you secure. Less than 10 seconds is not recommended.
iatyesCreation date. POSIX time format in SEC.
issyesWidget ID is a unique identifier of the widget configuration. Can be copied from widget snippet or directly from your widget configuration 
jtiyesGeneric ID of personalization token. You can put any string here. You must not use tokes with the same ID, they should always be unique. Personalization token ID (JTI), max length: 50 characters.
sidoptionalSession ID. It’s your unique generated session ID which can be used for session invalidation API. For each customer login, the session SID parameter should always be unique. Session ID (SID), max length: 50 characters.If you rely only on the logout method of Widget API, you can skip this parameter.
skiyesID of your generated security key. 
stpyesShould be explicitly defined as a type of 'sub' value. Available types:
  • email
  • msisdn
  • externalPersonId
Strict naming to be used.  
subyes

Your customer's unique identifier.
Email should not contain any white spaces, nor mismatch email format. Use only digits for phone number. externalPersonId is a usual String limited to 100 symbols.
Example: [email protected]

Example

json
 
     alg: "HS256"
    }.
    {
     jti: "f69fbb80-2967-4985-afae-6cfe6c0786c4",
     sub: "[email protected]",
     stp: "email",
     iss: "e7de374f-e590-4429-ae2d-54be7e90a356",
     iat: 1582700204,
     exp: 1582700264,
     ski: "52",
     sid: "85a53925-7bbb-46be-84f8-2b00c4a48a4d"
    }.
    xqDTU5RYS-KJRL7zyuwra2PDfZBNDHI3bbZHHrjQUjA
 
Example of a generated personalization token

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJLb25zdGFudGluLnZhbGlvdHRpQGluZm9iaXAuY29tIiwia2lkIjoz LCJpc3 MiOiJDaGF0VGVzdEFwcENvZGUiLCJpYXQiOjE1ODI5MDI1MzcsInNrdCI6ImVtYWlsIiwianRpIjoiODVh NTM5 MjUtN2JiYi00NmJlLTg0ZjgtMmIwMGM0YTQ4YTRkIn0.xqDTU5RYS-KJRL7zyuwra2PDfZBNDHI3bbZHHrjQUjA

Enable authenticated customer session with widget API

All Widget APIs follow the structure:

liveChat(command [, input] [, output handler callback function]);

The callback parameter is optional for handling errors from the Live Chat widget (no connection, connection lost, bad request, etc). For all commands, input is always required.

On your website customer login page, sign the chat session with your authenticated customer date by widget JS API:

liveChat('auth', '[personalizationToken]');

Example of 'auth' method with callback:

javascript
 
    liveChat('auth', '[personalizationToken]', function(error, result) {
      if (error) {
        ... // do process error
        console.log(error.code, error.message)
      } else {
      ... // no errors
      }
    });
 

Invalidate authenticated customer session

Here's how to invalidate an authenticated customer session:

Logout Widget API for Authenticated Session Invalidation

In cases where the end customer explicitly logs out, use the widget API logout method:

liveChat('logout', [callback]);

Example:

javascript
 
    liveChat('logout', null, function(error, result) {
      if (error) {
        ... // do process error
        console.log(error.code, error.message)
      } else {
      ... // no errors
      }
    });
 

Session Invalidation With Infobip Public API

As an alternative to the logout method in widget API, you can use invalidation session API (opens in a new tab) on Infobip public API. Invalidation session API can only be used only if back in the personalization token generator you've added the SID parameter.

When a specific session ID (SID) invalidation call is performed, the chat session in the widget is immediately reset to the anonymous session. The reset session erases the message history until the next login of the authenticated customer.

Personalization token generator code examples

You can use one of the prepared code examples for your backend services to generate personalization token for your authenticated customers in Infobip Live Chat widget.

IMPORTANT

Do not forget to decode from Base64 'key' value before signing token.

Examples of personalization token generator:

  • PHO
  • NodeJS
  • Java
  • Kotlin
  • Swift

PHP Implementation

php
 
    // Download PHP-JWT: https://github.com/firebase/php-jwt
    composer require firebase/php-jwt
    use \Firebase\JWT\JWT;
    $timestamp = time();
    $securityKey = json_decode('Copied data from Infobip Live Chat Security Key');
    $payload = {
      'jti' => 'random UNIQUE String',
      'stp' => '[email | msisdn | externalPersonId]',
      'sub' => '[[email protected] | +PhoneNumber | ExtPersonID]',
      'iss' => 'Widget ID',
      'iat' => $timestamp,
      'exp' => $timestamp + 15,
      'ski' => $securityKey->id,
      'sid' => 'Session Identifier'
    };
     $token = JWT::encode($payload, base64_decode($securityKey->key));
 

NodeJS Implementation

nodejs

    // Install jsonwebtoken: npm install jsonwebtoken --save-dev
    var jwt = require('jsonwebtoken');
    const securityKey = JSON.parse('Copied data from Infobip Live Chat Security Key');
    const timestamp = Math.floor(date.getTime()/1000);
    var payload = {
      jti: 'random UNIQUE String',
      stp: '[email | msisdn | externalPersonId]',
      sub: '[[email protected] | +PhoneNumber | ExtPersonID]',
      iss: 'Widget ID',
      iat: timestamp,
      exp: timestamp + 15,
      ski: securityKey.id,
      sid: 'Session Identifier'
    };
    var token = jwt.sign(payload, Buffer.from(securityKey.key, 'base64'));

JAVA Implementation

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.*;
 
    @Component
    class PersonalisationTokenGenerator {
      // IMPORTANT: securityKey here it is a copied data from Infobip Live Chat Security Key
      public ResponseEntity authorize(String widgetId, String securityKey) {
        try {
          // simple example how personalizationToken issuing process could looks like:
          ObjectMapper objectMapper = new ObjectMapper();
          SecurityKeyHMAC secret = objectMapper.readValue(securityKey, SecurityKeyHMAC.class);
          MACSigner personalizationTokenSigner = new MACSigner(Base64.getDecoder().decode(secret.getKey()));
          JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
            // generate always UNIQUE ID because Infobip will remember it and not permit to use it twice! As ID can be used ant string
            .jwtID(UUID.randomUUID().toString())                                      // unique ID of this token. Mandatory
            .subject("[email protected]")                                     // person destination in Infobip People service. Mandatory
            .issuer(widgetId)                                                         // which widget it belongs. Mandatory
            .issueTime(new Date())                                                        // when created. Mandatory
            .expirationTime(Date.from(Instant.now().plusMillis(15000))) // Optional, e.g. when this token should be invalidated if not yet used,
            // if not set then by default token will be invalidated after 15 seconds after issueTime
            .claim("ski", secret.getId())                                                 // needs for security validation. Mandatory
            .claim("stp", "email")                                                   // type of person destination in Infobip People service. Mandatory
            .claim("sid", "Session identifier")                                      // unique session identifier. Optional
            .build();
          SignedJWT personalizedToken = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
          personalizedToken.sign(personalizationTokenSigner);
          return ResponseEntity.ok(personalizedToken.serialize());
        } catch (Exception ex){
          // do some logging stuff
          ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
      }
    }
 
    class SecurityKeyHMAC {
      private long id;
      private String key;
 
      public long getId() {
        return id;
      }
 
      public void setId(long id) {
        this.id = id;
      }
 
      public String getKey() {
        return key;
      }
 
      public void setKey(String key) {
        this.key = key;
      }
    }
 

Kotlin Implementation

java
 
    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
    internal class PersonalisationTokenGenerator {
        // IMPORTANT: securityKey here it is a copied data from Infobip Live Chat Security Key
        fun authorize(widgetId: String?, securityKey: String?): ResponseEntity {
            try {
                // simple example how personalizationToken issuing process could looks like:
                val objectMapper = jacksonObjectMapper()
                val secret = objectMapper.readValue(securityKey, SecurityKeyHMAC::class.java)
                val personalizationTokenSigner = MACSigner(Base64.getDecoder().decode(secret.key))
                val claimsSet = JWTClaimsSet.Builder()                          // generate always UNIQUE ID because Infobip will remember it and not permit to use it twice! As ID can be used ant string
                    .jwtID(UUID.randomUUID().toString())                        // unique ID of this token. Mandatory
                    .subject("example-email@infobip.com")                       // person destination in Infobip People service. Mandatory
                    .issuer(widgetId)                                                            // which widget it belongs. Mandatory
                    .issueTime(Date())                                          // when created. Mandatory
                    .expirationTime(Date.from(Instant.now().plusMillis(15000))) // Optional, e.g. when this token should be invalidated if not yet used,
                    // if not set then by default token will be invalidated after 15 seconds after issueTime
                    .claim("ski", secret.id)                                    // needs for security validation. Mandatory
                    .claim("stp", "email")                                      // type of person destination in Infobip People service. Mandatory
                    .claim("sid", "Session identifier")                         // unique session identifier. Optional
                    .build()
                val personalizedToken = SignedJWT(JWSHeader(JWSAlgorithm.HS256), claimsSet)
                personalizedToken.sign(personalizationTokenSigner)
                return ResponseEntity.ok(personalizedToken.serialize())
            } catch (ex: Exception) {
                // do some logging stuff
                ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()
            }
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()
        }
    }
 
    data class SecurityKeyHMAC(val id: Long, val key: String)
 

Swift Implementation

swift
 
    // Download Swift-JWT: https://github.com/Kitura/Swift-JWT or any JSON Web Token library for Swift
    import SwiftJWT
    struct JWTClaims: Claims {
        let jti: String // random UNIQUE String. Mandatory.
        let sub: String // '[[email protected] | +PhoneNumber | ExtPersonID]'. Mandatory.
        let stp: String // Define the above. ie: "email", "msisdn" or "externalPersonId". Mandatory.
        let iss: String // Livechat widget Id. Mandatory.
        let iat: Date // timestamp. Mandatory. Issue time when created. Mandatory.
        let exp: Date // timestamp. Optional, e.g. when this token should be invalidated if not yet used. Default of 15 seconds. Mandatory.
        let ski: String // securityKey.id (provided by livechat widget, different that widget id). Mandatory.
        let sid: String // 'Session Identifier'. Optional
    }
    let myHeader = Header()
    let randomUniqueString = UUID().uuidString
    let myClaims = JWTClaims(
        jti: randomUniqueString,
        sub: email,
        stp: "email",
        iss: widgetId,
        iat: Date(),
        exp: Date().addingTimeInterval(20), // 20 seconds after creation - recommended value
        ski: widgetKeyId,
        sid: randomUniqueString)
    var myJWT = JWT(header: myHeader, claims: myClaims)
    guard let secretKeyIdData = Data(base64Encoded: widgetSecretKeyId, options: .ignoreUnknownCharacters) else {
        print("Unable to decode the base64 secret key Id")
        return nil
    }
    let jwtSigner = JWTSigner.hs256(key: secretKeyIdData)
    guard let signedJWT = try? myJWT.sign(using: jwtSigner) else {
        print("Unable to prepare the signed JWT to authenticate into the chat")
        return nil
    }
    // signedJWT is your JSON Web Token ready to use
 

Need assistance

Explore Infobip tutorials

Encountering issues

Contact our support

What's new? Check out

Release notes

Unsure about a term? See

Glossary

Research panel

Help shape the future of our products
Service Terms & ConditionsPrivacy policyTerms of use