The Chat SDK v2.8.0 iOS or later and v3.0.0 Android or later supports user authentication so that you can authenticate your Chat users for more familiar and secure interactions. For details, see the developer documentation: iOS | Android.

This article gives an overview of how you can use the API through Swift and Kotlin/Java. Topics covered:

Overview

You can configure your Chat SDK to authenticate users on initialization using the new setIdentity API alongside a JWT service.

When you configure the Chat SDK to authenticate users, you get the following benefits:

  • Higher confidence and security that the users or customers that you or your agents are talking to are real.
  • Support for cross-domain traffic: If you are embedding the SDK on multiple domains or link to externally hosted services such as Shopify, authenticating the visitor will persist that visitor's identity across the domains to the Chat platform, which allows your agent to have more context.
  • Support for cross device or browser identification: The visitor can be viewed as the same person if or when they choose to use a different device or browser when the custom ID is specified in the authentication call.

Unlike the Zendesk Chat Web Widget, authenticating your users in the SDK won’t enable them to see their Chat history. This is a technical limitation of the SDK.

Prerequisites

There are a couple of steps you need to do before diving into the article. Completing these steps will ensure you are prepared to read through the article with ease. It's likely the prerequisites will be done by your server-side team that handle user authentication, but it's important information to be aware off.

The following steps are required to handle authenticated users:

Generating a Chat shared secret

To configure the SDK for end user authentication, you'll need a shared secret. A shared secret is a security setting intended to be generated, copied, and pasted into a communication with your engineering team, or directly into your code base, in a single sitting. It should not be entered into a browser, or in to the source code of your application.

Only Chat administrators can configure visitor authentication settings.

To generate the shared secret required for authenticated visitors

  1. Open your Chat dashboard and go to Settings > Widget.
  2. Click the Widget Security tab.
  3. Scroll down to the Visitor Authentication section and click the Generate button.
Note: The shared secret is intended to remain secure. As a result, it will only appear in full only one time. If you don’t have access to the shared secret and need the full secret to create your token, you can reset the secret by clicking the Regenerate button.

Regenerating a new shared secret will revoke the previous token. If you have concerns the shared secret has been compromised, you should regenerate a new one. If you need to rotate the keys, you should schedule it when Chat is offline because regenerating the secret may cause visitors to be disconnected from the SDK for 5 minutes.

Ensure that you communicate any changes to the secret with other teams that might be handling authentication (like the team handling the web widget).

Once you have generated the shared secret, you'll be ready to use it to create a JWT token. Learn more about JWT. This token will eventually be passed into the instance of the Chat SDK.

Creating a JWT token

The JWT token needs to be dynamically generated from the server-side. Your server-side developers will probably provide you with an endpoint to retrieve the token. You will need to prepare your application to reach this endpoint.

Construct a server-side payload of data for the JWT token. This needs to have the following information:

  • name: Customer's name
  • email: Customer's email
  • external_id: alphanumeric string, unique to identifying the customer. Once set for the customer, this value cannot be changed. We recommend that you use your system's unique user ID for this field. For example, user-123456. Max length is 200 characters
  • iat: Integer value of the current timestamp, in seconds. Some functions in specific languages Iat for Chat authentication permits up to two minutes clock skew.
  • exp: (optional) Integer value of the expiry timestamp, in seconds. This value indicates when this JWT token will expire. The value is permitted to be up to a maximum of 7 minutes from the iat value.

If the endpoint isn't prepared, and for ease of testability, you can set up a local service by implementing one of these code samples.

How to authenticate your users

Once your JWT service is set up to emit valid JWT tokens, and your application is prepared with an access point to this service, you will be ready to enable authenticated Chat users in your application.

It's easy to set up your application to authenticate your users in your Chat instance. There are two steps that you need to follow. Once they're complete, your users will be authenticated in the Chat dashboard. How this looks like is covered later in the article.

To enable authenticated Chat users:

  1. Conform to the JWTAuthenticator protocol
  2. Call setIdentity on the Chat instance

Conform to the JWTAuthenticator protocol (interface)

The JWTAuthenticator protocol (interface) contains one function (getToken) that needs to be implemented.
It's likely your authentication provider will contain a function that emits a response from your JWT service.

On iOS, the getToken function has a completion block that takes a tuple of type optional String and optional Error.

On Android, the getToken method takes a callback which has two methods, onTokenLoaded(String) and onError()

Pass in the result of your authentication provider's callback into the completion block, and the Chat SDK will appropriately handle the success and failure of the completion handler.

If the request to the JWT service emits an error, the Chat SDK will fallback to an anonymous (non-authenticated) user.

Here is an implementation of a Swift class that conforms to the JWTAuthenticator protocol.

final class JWTAuth: NSObject, JWTAuthenticator {   func retrieveToken(_ completion: @escaping (Result<String, Error\>) -> Void) {   // request to backend service that returns a JWT Token or an Error   }     func getToken(_ completion: @escaping (String?, Error?) -> Void) {   retrieveToken { (result) in   completion(result.tuple.0, result.tuple.1)   }   }  }    extension Result { // Helper to convert Swift Result to tuple for Objective-C style result   var tuple: (Success?, Failure?) {   switch self {   case .success(let success):   return (success, nil)   case .failure(let error):   return (nil, error)   }   }  }

Here is an implementation of a Java class that conforms to the JWTAuthenticator interface:

class JwtAuth implements JwtAuthenticator {        private void retrieveToken(JwtCallback callback) {          // request to backend service that returns a JWT Token or an Error       }         @Override       public void getToken(final JwtCompletion jwtCompletion) {           retrieveToken(new JwtCallback() {               @Override               public void onSuccess(String token) {                   jwtCompletion.onTokenLoaded(token);               }                 @Override               public void onError() {                   jwtCompletion.onError();               }           });       }         interface JwtCallback {           void onSuccess(String token);           void onError();       }   }

Call setIdentity on the Chat instance

Once you have a class that conforms to the protocol (implements the interface) and retrieves a JWT from the authentication service, you will be ready to apply it to your Chat instance.

You will need to do this after initialization of your Chat instance. If you contain your Zendesk-related code in a single wrapper class, the setIdentity call can be done in the init. You will need to pass in an instance of the class that implements the JWTAuthenticator protocol (interface).

Swift snippet of calling setIdentity.

final class ZendeskChat {    static let instance = ZendeskChat()     func initialize() {   Chat.initialize(accountKey: accountKey, appId: appId)   let auth = JWTAuth()   Chat.instance?.setIdentity(authenticator: auth)   }  }

Java snippet of calling setIdentity**.
**

public enum ZendeskChat {      INSTANCE;        ZendeskChat() {          Chat.INSTANCE.init(context, accountKey);          JwtAuthenticator jwtAuth = new JwtAuth();          Chat.INSTANCE.setIdentity(jwtAuth);      }  }

After you've called setIdentity passing in a valid implementation of the JWTAuthenticator protocol, you will have Chat authentication enabled, and ready to use. All you need to do is start a chat, type a message, and you should see in the agent dashboard that your user is authenticated.

About the agent experience with authenticated visitors

A few things are updated in the Chat dashboard when an agent starts chatting with an authenticated user.

First, the agent will be able to tell the user is authenticated by the green authenticated checkmark overlay on the user's avatar:

If your instance of Zendesk has the Agent Workspace experience, you should see a tick beside the user's messages. This allows the agent to know the user is authenticated

The agent will also notice that they cannot edit the visitor's name or email, since the source of truth comes from the information being sent via the JWT.

Finally, banning an authenticated visitor will mean the visitor cannot start a Chat from either the Web Widget and or the SDKs.

About the Chat SDK experience for authenticated users

The experience for authenticated users is almost identical to that of an anonymous user.

Since the user's information is read-only, it can't be modified by them using the pre-chat form or the ChatAPIConfiguration

Therefore, the pre-chat and offline forms won't contain any queries about their information (such as name, email or phone).

The user will only be asked about their initial query and which department they'd like to be directed towards (configurable through ChatConfiguration).

Troubleshooting

The Chat SDK will proceed with an un-authenticated session if there is any error in the process of authenticating the user. If you are having issues with setting up authentication, there are a few things you can try to ensure you're following the steps correctly.

  1. Validate your token with your secret on jwt.io
  2. Listen for authentication errors notifications (iOS only)

Authentication error notifications (iOS Only)

If you've verified the tokens you are retrieving, and are still failing to see authenticated users, you can listen for authentication errors in your application, and handle the errors appropriately. You can find the list of error cases in the developer documentation.

On Android we do not currently support this style of notifiction, however if any errors occur we will log the error. To view SDK logs, you need to enable logging by calling Logger.setLoggable(true).

The following Swift snippet listens for AuthenticationErrors.

private func observeAuthNotification() {   NotificationCenter.default.addObserver(self,   selector: #selector(authenticationHasFailed(_:)),   name: Chat.NotificationAuthenticationFailed,   object: nil)  }    @objc func authenticationHasFailed(_ notification: Notification) {   guard let error = notification.userInfo?[NSUnderlyingErrorKey] as? AuthenticationError else { return }   switch error {   case .invalidAccessToken(let token):   // Provided JWT token is invalid   @unknown default:   break   }  }

How to un-authenticate your users

You might want to un-authenticate your users at some point, whether they are removing their accounts or just logging out. You can do this through the resetIdentity function on the Chat instance. The function takes an optional completion handler to perform any actions that might be required to carry out after the identity is fully reset.

The following Swift snippet calls resetIdentity.

extension ZendeskWrapper {   func resetIdentity() {   Chat.instance?.resetIdentity {   // Identity cleared, continue to log out   }   }  }

Java snippet of calling resetIdentity.

public enum ZendeskChat {      INSTANCE;        void resetIdentity() {          Chat.INSTANCE.resetIdentity(new CompletionCallback<Void>() {              // Identity cleared, continue to log ou          });      }  }

Now your agents can have secure and familiar conversations with your customers through your application.

If you're still having trouble setting up your authenticated flow, see the Sample app prepared with a local JWT service (mentioned above): iOS sample | Android sample (TBA).