User types
In this article, we will discuss the difference between Leads and Authenticated Customers using your Live Chat web widget.
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.
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:
- Generate a secret key from your widget configuration.
- Implement personalization token generator on your website backend application.
- Add Widget API auth method to your authenticated customers' chat session.
- 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:
Copy the key to your clipboard (here's an example):
{"id":3,"key":"7Q25YT4fKM7G+BO/7QyW9vdF/YC8zBN3w4HQPyKgk98="}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.
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)
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:
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.
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:
Parameter | Mandatory | Description |
---|---|---|
alg | yes | Encryption algorithm. Supported value HS256 . |
exp | optional | Token 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. |
iat | yes | Creation date. POSIX time format in SEC. |
iss | yes | Widget ID is a unique identifier of the widget configuration. Can be copied from widget snippet or directly from your widget configuration |
jti | yes | Generic 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. |
sid | optional | Session 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. |
ski | yes | ID of your generated security key. |
stp | yes | Should be explicitly defined as a type of 'sub' value. Available types:
|
sub | yes | Your customer's unique identifier. |
Example
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
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:
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:
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.
Do not forget to decode from Base64 'key' value before signing token.
Examples of personalization token generator:
- PHO
- NodeJS
- Java
- Kotlin
- Swift
PHP Implementation
// 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
// 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
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
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
// 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