Skip to content

Commit

Permalink
support jwt token for zendesk auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Yen Truong committed Dec 4, 2024
1 parent dc8d0ce commit 601eeb7
Show file tree
Hide file tree
Showing 15 changed files with 138 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/chat-core-zendesk](./chat-core-zendesk.md) &gt; [ChatCoreZendeskConfig](./chat-core-zendesk.chatcorezendeskconfig.md) &gt; [externalId](./chat-core-zendesk.chatcorezendeskconfig.externalid.md)

## ChatCoreZendeskConfig.externalId property

The external ID to associate with the user in Zendesk.

**Signature:**

```typescript
externalId?: string;
```

## Remarks

Should be provided along with the [ChatCoreZendeskConfig.jwt](./chat-core-zendesk.chatcorezendeskconfig.jwt.md) token to authenticate the user.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/chat-core-zendesk](./chat-core-zendesk.md) &gt; [ChatCoreZendeskConfig](./chat-core-zendesk.chatcorezendeskconfig.md) &gt; [jwt](./chat-core-zendesk.chatcorezendeskconfig.jwt.md)

## ChatCoreZendeskConfig.jwt property

The JWT token to authenticate the user with Zendesk.

**Signature:**

```typescript
jwt?: string;
```

## Remarks

Should be provided along with the [ChatCoreZendeskConfig.externalId](./chat-core-zendesk.chatcorezendeskconfig.externalid.md) to authenticate the user.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ export interface ChatCoreZendeskConfig

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [externalId?](./chat-core-zendesk.chatcorezendeskconfig.externalid.md) | | string | _(Optional)_ The external ID to associate with the user in Zendesk. |
| [integrationId](./chat-core-zendesk.chatcorezendeskconfig.integrationid.md) | | string | The web widget integration ID for the Zendesk chat. |
| [jwt?](./chat-core-zendesk.chatcorezendeskconfig.jwt.md) | | string | _(Optional)_ The JWT token to authenticate the user with Zendesk. |
| [onInvalidAuth?](./chat-core-zendesk.chatcorezendeskconfig.oninvalidauth.md) | | () =&gt; string \| Promise&lt;string&gt; | _(Optional)_ Callback to be invoked when the authentication token is invalid. The returned string will be used as the new auth token when retrying the request. |
| [ticketTags?](./chat-core-zendesk.chatcorezendeskconfig.tickettags.md) | | string\[\] | _(Optional)_ Tags to apply when handoff to Zendesk is initiated. |

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/chat-core-zendesk](./chat-core-zendesk.md) &gt; [ChatCoreZendeskConfig](./chat-core-zendesk.chatcorezendeskconfig.md) &gt; [onInvalidAuth](./chat-core-zendesk.chatcorezendeskconfig.oninvalidauth.md)

## ChatCoreZendeskConfig.onInvalidAuth property

Callback to be invoked when the authentication token is invalid. The returned string will be used as the new auth token when retrying the request.

**Signature:**

```typescript
onInvalidAuth?: () => string | Promise<string>;
```
3 changes: 3 additions & 0 deletions packages/chat-core-zendesk/etc/chat-core-zendesk.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export interface ChatCoreZendesk {

// @public
export interface ChatCoreZendeskConfig {
externalId?: string;
integrationId: string;
jwt?: string;
onInvalidAuth?: () => string | Promise<string>;
ticketTags?: string[];
}

Expand Down
2 changes: 1 addition & 1 deletion packages/chat-core-zendesk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yext/chat-core-zendesk",
"version": "0.2.0",
"version": "0.3.0",
"description": "Typescript Networking Library for the Yext Chat API Integration with Zendesk",
"main": "./dist/commonjs/index.js",
"module": "./dist/esm/index.mjs",
Expand Down
51 changes: 34 additions & 17 deletions packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export class ChatCoreZendeskImpl implements ChatCoreZendesk {
private conversationId: string | undefined;
private integrationId: string;
private tags: string[] = ["yext-chat-agent-handoff"];
private jwt?: string;
private externalId?: string;
private onInvalidAuth?: () => string | Promise<string>;

constructor(config: ChatCoreZendeskConfig) {
if (window === undefined) {
Expand All @@ -58,6 +61,9 @@ export class ChatCoreZendeskImpl implements ChatCoreZendesk {
this.integrationId = config.integrationId;
this.tags = [...this.tags, ...(config.ticketTags ?? [])];
this.tags = [...new Set(this.tags)];
this.jwt = config.jwt;
this.externalId = config.externalId;
this.onInvalidAuth = config.onInvalidAuth
}

/**
Expand All @@ -74,24 +80,35 @@ export class ChatCoreZendeskImpl implements ChatCoreZendesk {

private async initializeZendeskSdk(): Promise<void> {
const divId = "yext-chat-core-zendesk-container";
if (!window.document.getElementById(divId)) {
const div = window.document.createElement("div");
window.document.body.appendChild(div);
div.id = divId;
div.style.display = "none";
Smooch.render(div);
try {
await Smooch.init({
integrationId: this.integrationId,
embedded: true,
soundNotificationEnabled: false,
});
} catch (e) {
console.error("Zendesk SDK init error", e);
throw e;
}
this.setupEventListeners();
if (window.document.getElementById(divId)) {
return;
}
const div = window.document.createElement("div");
window.document.body.appendChild(div);
div.id = divId;
div.style.display = "none";
Smooch.render(div);

// Smooch.init() returns a Thenable object, not an actual Promise.
// So we can't use await syntax. Instead, we use try/catch to handle errors.
return new Promise((resolve, reject) => {
Smooch.init({
integrationId: this.integrationId,
embedded: true,
soundNotificationEnabled: false,
...(this.jwt && { jwt: this.jwt }),
...(this.externalId && { externalId: this.externalId }),
delegate: {
onInvalidAuth: this.onInvalidAuth,
},
}).then(() => {
this.setupEventListeners();
resolve();
}).catch((e) => {
console.error("Zendesk SDK init error", e);
reject(e);
});
});
}

/**
Expand Down
19 changes: 19 additions & 0 deletions packages/chat-core-zendesk/src/models/ChatCoreZendeskConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,23 @@ export interface ChatCoreZendeskConfig {
* Tags to apply when handoff to Zendesk is initiated.
*/
ticketTags?: string[];
/**
* The JWT token to authenticate the user with Zendesk.
*
* @remarks
* Should be provided along with the {@link ChatCoreZendeskConfig.externalId} to authenticate the user.
*/
jwt?: string;
/**
* The external ID to associate with the user in Zendesk.
*
* @remarks
* Should be provided along with the {@link ChatCoreZendeskConfig.jwt} token to authenticate the user.
*/
externalId?: string;
/**
* Callback to be invoked when the authentication token is invalid.
* The returned string will be used as the new auth token when retrying the request.
*/
onInvalidAuth?: () => string | Promise<string>;
}
3 changes: 3 additions & 0 deletions packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ beforeEach(() => {
jest
.mocked(SmoochLib.createConversation)
.mockResolvedValue({ id: mockConversationId } as Conversation);
jest
.mocked(SmoochLib.init)
.mockResolvedValue(Promise.resolve());
document.body.innerHTML = "";
});

Expand Down
2 changes: 2 additions & 0 deletions test-sites/test-browser-esm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ This will serve the index.html page on http://localhost:5050. Opening that up sh
#### Zendesk

To test Zendesk integration, ensures that the bot is configured with Zendesk handoff goal and provided appropriate credentials. In the `.env` file, provide the value for `TEST_ZENDESK_INTEGRATION_ID`. The test site should switch to use ChatCoreZendesk instance if it detects a zendesk-specific handoff step.

For agent handoff with zendesk user assigned as requester, authentication is needed via providing JWT token and externalId to zendesk core. In the `.env` field, provide the value for `TEST_EXTERNAL_ID` and `TEST_JWT`. To test jwt refresh logic, provide `TEST_REFRESH_JWT`, which should be used when the initial jwt token expires.
14 changes: 7 additions & 7 deletions test-sites/test-browser-esm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 1 addition & 7 deletions test-sites/test-browser-esm/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@ export default {
plugins: [
replace({
//inject env values
"process.env.TEST_BOT_API_KEY": JSON.stringify(
process.env.TEST_BOT_API_KEY
),
"process.env.TEST_BOT_ID": JSON.stringify(process.env.TEST_BOT_ID),
"process.env.TEST_ZENDESK_INTEGRATION_ID": JSON.stringify(
process.env.TEST_ZENDESK_INTEGRATION_ID
),
"REPLACE_ME_WITH_ENV_VALUES": JSON.stringify(process.env),
}),
resolve({
//resolve paths
Expand Down
7 changes: 6 additions & 1 deletion test-sites/test-browser-esm/sample.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
TEST_BOT_ID=
TEST_BOT_API_KEY=
TEST_ZENDESK_INTEGRATION_ID=
TEST_ZENDESK_INTEGRATION_ID=

# agent handoff with zendesk user authentication
TEST_EXTERNAL_ID=
TEST_JWT=
TEST_REFRESH_JWT=
10 changes: 9 additions & 1 deletion test-sites/test-browser-esm/src/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { StreamEventName, provideChatCore } from "@yext/chat-core";
import { provideChatCoreAwsConnect } from "@yext/chat-core-aws-connect";
import { provideChatCoreZendesk } from "@yext/chat-core-zendesk";

// will be replace with actual env value during rollup build process
const process = { env: REPLACE_ME_WITH_ENV_VALUES };

let chatCore = provideChatCore({
// will be replace with actual env value during rollup build process
apiKey: process.env.TEST_BOT_API_KEY || "API_KEY_PLACEHOLDER",
botId: process.env.TEST_BOT_ID,
endpoints: {
Expand Down Expand Up @@ -64,6 +66,12 @@ window.getNextMessage = async () => {
agentCore = provideChatCoreZendesk({
integrationId: process.env.TEST_ZENDESK_INTEGRATION_ID,
ticketTags: ["testingTag"],
jwt: process.env.TEST_JWT,
externalId: process.env.TEST_EXTERNAL_ID,
onInvalidAuth: () => {
console.log("onInvalidAuth: return TEST_REFRESH_JWT");
return process.env.TEST_REFRESH_JWT;
}
});
handleHandoff(data);
}
Expand Down

0 comments on commit 601eeb7

Please sign in to comment.