> ## Content Index
> Fetch the complete content index at: https://internalnote.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Authenticate Zendesk Messaging
- URL: https://internalnote.com/jwt-messaging/
- Published: 2022-05-30T14:39:00.000Z
- Updated: 2025-12-02T17:57:51.000Z
- Description: Zendesk recently added the ability to authenticate users in the Zendesk Messaging Web and Mobile SDK. This article shows how to set it up with sample code.
- Author: Thomas Verschoren
- Tags: Security & Privacy

⚠️

Apparently old Zendesk accounts can be tagged with an internal flag that prevents External ID matching to work. Zendesk Support removed the flag from my account and External ID tagging now works as expected. [Look at this article for more info](https://internalnote.com/deepdive-into-messaging-profiles/).  
  
This means Email matching is still an issue, but External IDs do work!

Zendesk recently added the ability to authenticate users in the Zendesk Messaging Web and Mobile SDK. This article shows how to set it up with sample code.

Zendesk recently added the ability to [authenticate users in the Zendesk Messaging](https://developer.zendesk.com/documentation/zendesk-web-widget-sdks/sdks/web/sdk%5Fapi%5Freference/?ref=internalnote.com#authentication) Web and Mobile SDK. This allows any website or app that has logged in users to pass that information to Zendesk so that you're sure you're talking to the right person, and removes the need for your customer to enter any credentials.

Setting it up is easy, as long as you have a working JWT endpoint. If you haven't got one, this guide will show you how to set one up using Cloudflare Workers.

Note that this example code does not validate the user against any directory. It trust the input and returns a valid JWT for Zendesk to use.

[See Demo](https://demo.internalnote.com/messaging.html?ref=internalnote.com)

## How it works

Let's start at the end of the flow and show a working scenario.

1. A user visits [https://demo.internalnote.com/messaging.html](https://demo.internalnote.com/messaging.html?ref=internalnote.com)
2. They enter their name/email and press login
3. The website logs in the user and the widget authenticates
4. Zendesk recognises the user, and starts a conversation.

If there's still an ongoing conversation from earlier, the widget will show the conversation regardless of the user having used that browser/device before.

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/messaging_0003_Screenshot-2022-05-31-at-21.30.31.jpg)

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/messaging_0002_Screenshot-2022-05-31-at-21.30.45-1.jpg)

When the agent opens the conversation in the Agent Workspace he notices a green checkbox next to the users' name showing them the user has logged in correctly.

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/messaging_0000_Layer-2.jpeg)

💡

Note: Zendesk has different approaches on how to map Messaging users to existing user profiles. Take a look [here](https://internalnote.com/messaging-authentication-identify-and-merge-existing-users?utm%5Fsource=demo) for more information

## Setting up Authentication

Authenticating a user requires the following steps:

1. Get a Secret and App ID from Zendesk
2. Create a web service (e.g. via Cloudflare Workers) to generate a valid Valid JWT
3. Have a function on your website that calls the web service when a user logs in and generates a JWT based on their email, name and ID
4. Push that JWT Token to the Widget

### Credentials

Setting up authentication for Messaging first requires generating a Secret and App ID. That's done via [https://subdomain.zendesk.com/admin/account/security/end\_users#messaging](https://subdomain.zendesk.com/admin/account/security/end%5Fusers?ref=internalnote.com#messaging)

```html
App ID: app_12345abcde1234567890
Secret: some-very-long-string-with-digits-and-numbers
```

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/Screenshot-2022-05-31-at-20.26.06.png)

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/Screenshot-2022-05-31-at-20.26.11.png)

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/Screenshot-2022-05-31-at-20.26.14.png)

To generate a login for the web widget you'll also need a name, email and external ID for your user.

## Generating the JWT

Based on the above items you can generate a working JWT. You can find an example below.

There's a few important caveats:

- External ID has to be unique for each user, so use a GUID, UUID, or database ID
- The credentials do not expire unless you set an expiration date
- We pass `email_verified: true` so that Zendesk will handle the email address as a verified address to work with the new [email identity](https://internalnote.com/messaging-authentication-identify-and-merge-existing-users?utm%5Fsource=demo) rules.

💡

Note that our sample code does ****not** integrate with your actual directory and as such we can not validate if the user you're logging in actually exists. That's something you need to implement yourself!

```javascript
var input = {
    "external_id":1906365876753,
    "user_email":"john@example.com",
    "user_name":"John Smith"
}

const app_id = "app_123";
const secret ="abc123";

const key = await crypto.subtle.importKey(
   "raw",
   utf8ToUint8Array(secret),
   { name: "HMAC", hash: "SHA-256" },
   false,
   ["sign"]
);

const header = JSON.stringify({ alg:"HS256", typ:"JWT", kid:app_id });

const payload = JSON.stringify({
  exp: Math.floor(new Date().getTime() / 1000.0) + 86400,
  scope: "user",
  name: json.user_name,
  email: json.user_email,
  external_id: external_id,
  email_verified: true
});

const partialToken = `${base64URLStringify(utf8ToUint8Array(header))}.${base64URLStringify(utf8ToUint8Array(payload))}`;

const signature = await crypto.subtle.sign(
	"HMAC",
    key,
    utf8ToUint8Array(partialToken)
);

const jwt = `${partialToken}.${base64URLStringify(new Uint8Array(signature))}`;
```

For the example website above I created a Cloudflare Worker that handles the JWT scenario for both Messaging and the Classic Widget.

You can find a working code example via the link below. 

[GitHub - verschoren/zendesk\_widget: Zendesk has a nice Web Widget to embed your contact channels and FAQ on any page of your website creating a consistent experience that aligns with your brand.Zendesk has a nice Web Widget to embed your contact channels and FAQ on any page of your website creating a consistent experience that aligns with your brand. - GitHub - verschoren/zendesk\_widget:…![](https://github.githubassets.com/pinned-octocat.svg)GitHubverschoren![](https://repository-images.githubusercontent.com/647671522/79e4a3b1-3853-4473-983f-c8bcf28c922f)](https://github.com/verschoren/zendesk%5Fwidget?ref=internalnote.com)

### Logging In

The end result is a JWT token that you pass to the widget via:

```javascript
zE('messenger', 'loginUser', function (callback) { 
    callback(jwttoken);
});
```

### Logging Out

If for any reason you wish to logout your user, you can use the code below.

```javascript
zE('messenger', 'logoutUser');
```

## What about Zendesk Guide?

You can also easily use the above example to authenticate Zendesk Guide.

1. Open your Zendesk Guide Theme and [edit its code](https://support.zendesk.com/hc/en-us/articles/4408832558874-Editing-the-code-for-your-live-help-center-theme?ref=internalnote.com)
2. Open `document_head.hdbs` and paste the[ following code](https://demo.internalnote.com/guide%5Fmessaging?ref=internalnote.com) at the bottom
3. From now on, whenever a user logs into your Help Center, the widget will authenticate itself.

![](https://storage.ghost.io/c/ca/c0/cac0c82b-bc4d-4404-9eb4-9cc75e8d045e/content/images/2023/01/Screenshot-2022-05-31-at-22.12.47.png)