-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEAT_ Zendesk #1794
Open
jwalsh-vori
wants to merge
12
commits into
baptisteArno:main
Choose a base branch
from
jwalsh-vori:FEAT_ZENDESK
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+253
−6
Open
FEAT_ Zendesk #1794
Changes from 5 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
d53ed0a
Initial commit
jwalsh-famkit ac7de53
cleaned up code
jwalsh-famkit d2fd1f6
updated to fix auth issue
jwalsh-famkit 87ce798
Merge branch 'baptisteArno:main' into FEAT_ZENDESK
jwalsh-vori cf04b7a
added docs
jwalsh-famkit 69ea220
📝 Improve Zendesk logo and add docs url
baptisteArno 36a1d28
Merge branch 'baptisteArno:main' into FEAT_ZENDESK
jwalsh-vori 409e400
Merge branch 'baptisteArno:main' into FEAT_ZENDESK
jwalsh-vori 56b015e
updated to add auth into single function
jwalsh-famkit a0a6583
removed ? from helperText
jwalsh-famkit 3d7177d
removed the authenticate action
jwalsh-famkit bf79112
Updated to simplify options
jwalsh-famkit File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
title: Zendesk | ||
--- | ||
|
||
## Zendesk Messaging | ||
|
||
With the Zendesk Chat block, you can open a Zendesk Messaging live chat window to allow a user to chat with a Zendesk agent. | ||
|
||
## How to find my Zendesk `Key ID` and `Secret Key`? | ||
|
||
To configure your Web Widget or mobile SDK for visitor authentication, you first need a signing key. A signing key is a type of credential which is comprised of a key id (kid) and a shared secret. | ||
|
||
You can view, create, and delete signing keys by clicking the Account icon in the Admin Center sidebar, and then selecting End user authentication under the Security heading ( you will need to be a Zendesk Admin). The shared secret will only be displayed in its entirety when the signing key is first created. | ||
|
||
<Frame> | ||
<img | ||
src="/images/blocks/integrations/zendesk/zendesk-end-user-auth.png" | ||
alt="End User Authentication" | ||
/> | ||
</Frame> | ||
|
||
Learn more here: https://developer.zendesk.com/documentation/zendesk-web-widget-sdks/sdks/web/enabling_auth_visitors/#generating-a-signing-key | ||
|
||
## Authenticate Messaging User | ||
|
||
This action will generate a JWT token that can be passed as a variable to Open Web Widget you to authenticate a user in Zendesk. It requires the `User ID`, `Name` `Email`. Optionally, you can also set `Email Is Verified` if the email address has been verified. This is recommended to be set if appropriate. | ||
|
||
Learn more here: https://developer.zendesk.com/documentation/zendesk-web-widget-sdks/sdks/web/enabling_auth_visitors/#email-verification. | ||
|
||
## Open Web Widget | ||
|
||
This action opens the Messenging Web Widget. It requires the Web Widget `Key` to be set. You can find the key by going to `Channels -> Messaging`, then click on the Web Widget you wish to configure. Scroll down to 'Installation' and expand that section. In the script code block, copy the `key` value and use that for the `Key` setting. | ||
|
||
Note, this only works on web clients. | ||
|
||
<Frame> | ||
<img | ||
src="/images/blocks/integrations/zendesk/web-widget-config.png" | ||
alt="Web Widget Key" | ||
/> | ||
</Frame> | ||
|
||
If `Enable User Authentication` is enabled, and a token is set in the `User Auth Token` field, the user will be authenticated in Zendesk. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+238 KB
apps/docs/images/blocks/integrations/zendesk/zendesk-end-user-auth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
packages/forge/blocks/zendesk/actions/authenticateMessagingUser.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { createAction, option } from '@typebot.io/forge' | ||
import { sign } from 'jsonwebtoken'; | ||
import { auth } from '../auth' | ||
|
||
export const authenticateMessagingUser = createAction({ | ||
name: 'Authenticate Messaging User', | ||
auth, | ||
options: option.object({ | ||
userId: option.string.layout({ | ||
label: 'User ID', | ||
isRequired: true, | ||
}), | ||
name: option.string.layout({ | ||
label: 'Name', | ||
isRequired: true, | ||
}), | ||
email: option.string.layout({ | ||
label: 'Email', | ||
isRequired: true, | ||
}), | ||
isEmailVerified: option.string.layout({ | ||
label: 'Is email verified', | ||
inputType: 'variableDropdown', | ||
isRequired: true | ||
}), | ||
tokenVariableId: option.string.layout({ | ||
label: 'Token variable', | ||
inputType: 'variableDropdown', | ||
isRequired: true | ||
}), | ||
}), | ||
run: { | ||
server: async ({ | ||
credentials: { conversationsSecretKey, conversationsKeyId }, | ||
options: { userId, name, email, isEmailVerified, tokenVariableId }, | ||
variables, | ||
}) => { | ||
if (!email || email.length === 0 | ||
|| !userId || userId.length === 0 | ||
|| !name || name.length === 0 | ||
|| conversationsSecretKey === undefined | ||
|| conversationsKeyId === undefined | ||
|| tokenVariableId === undefined | ||
) return | ||
variables.set(tokenVariableId, sign({ scope: 'user', external_id: userId, name: name, email: email, email_verified: "true" }, conversationsSecretKey, { algorithm: "HS256", keyid: conversationsKeyId })); | ||
} | ||
}, | ||
}) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { createAction, option } from '@typebot.io/forge' | ||
import { auth } from '../auth' | ||
|
||
export const openWebWidget = createAction({ | ||
auth, | ||
name: 'Open Web Widget', | ||
options: option.object({ | ||
key: option.string.layout({ | ||
label: "Web widget key", | ||
isRequired: true, | ||
}), | ||
isAuthEnabled: option.boolean.layout({ | ||
accordion: "Authentication", | ||
label: "Enable user authentication", | ||
defaultValue: false, | ||
}), | ||
token: option.string.layout({ | ||
accordion: "Authentication", | ||
label: "User auth token", | ||
isRequired: false | ||
}) | ||
}), | ||
run: { | ||
web: { | ||
parseFunction: ({ options }) => { | ||
return { | ||
args: { | ||
isAuthEnabled: options.isAuthEnabled ? options.isAuthEnabled?.toString() : "false", | ||
token: options.token ?? null, | ||
key: options.key ?? null | ||
}, | ||
content: parseOpenMessenger() | ||
} | ||
} | ||
}, | ||
}, | ||
}) | ||
|
||
const parseOpenMessenger = () => { | ||
return `(function (d, t) { | ||
var ZD_URL = "https://static.zdassets.com/ekr/snippet.js?key=" + key; | ||
|
||
var ze_script = d.createElement(t); | ||
var s = d.getElementsByTagName(t)[0]; | ||
|
||
ze_script.id="ze-snippet"; | ||
ze_script.src = ZD_URL; | ||
ze_script.crossorigin = "anonymous"; | ||
ze_script.defer = true; | ||
ze_script.async = true; | ||
s.parentNode.insertBefore(ze_script, s); | ||
|
||
ze_script.onload = function () { | ||
if ( isAuthEnabled === "true" ) { | ||
zE("messenger", "loginUser", function (callback) { | ||
callback(token); | ||
zE("messenger", "open"); | ||
}); | ||
} else { | ||
zE("messenger", "open"); | ||
} | ||
}; | ||
})(document, "script"); | ||
` | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { option, AuthDefinition } from '@typebot.io/forge' | ||
|
||
export const auth = { | ||
type: 'encryptedCredentials', | ||
name: 'Zendesk Conversations API', | ||
schema: option.object({ | ||
conversationsSecretKey: option.string.layout({ | ||
label: 'Conversations Secret Key', | ||
isRequired: true, | ||
inputType: 'password', | ||
withVariableButton: false, | ||
isDebounceDisabled: true, | ||
}), | ||
conversationsKeyId: option.string.layout({ | ||
label: 'Conversations Key ID', | ||
isRequired: true, | ||
withVariableButton: false, | ||
isDebounceDisabled: true, | ||
}) | ||
}), | ||
} satisfies AuthDefinition |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { createBlock } from '@typebot.io/forge' | ||
import { ZendeskLogo } from './logo' | ||
import { auth } from './auth' | ||
import { authenticateMessagingUser } from './actions/authenticateMessagingUser' | ||
import { openWebWidget } from './actions/openWebWidget' | ||
|
||
export const zendeskBlock = createBlock({ | ||
id: 'zendesk', | ||
name: 'Zendesk', | ||
tags: ['live chat', 'crm'], | ||
LightLogo: ZendeskLogo, | ||
auth, | ||
actions: [authenticateMessagingUser, openWebWidget], | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** @jsxImportSource react */ | ||
|
||
export const ZendeskLogo = (props: React.SVGProps<SVGSVGElement>) => ( | ||
<svg viewBox="0 0 256.00 256.00" {...props}> | ||
<g id="SVGRepo_bgCarrier" stroke-width="0" /> | ||
<g | ||
id="SVGRepo_tracerCarrier" | ||
stroke-linecap="round" | ||
stroke-linejoin="round" | ||
/> | ||
<g id="SVGRepo_iconCarrier"> | ||
<g> | ||
<path | ||
d="M118.249172,51.2326115 L118.249172,194.005605 L0,194.005605 L118.249172,51.2326115 Z M118.249172,2.84217094e-14 C118.249172,32.6440764 91.7686624,59.124586 59.124586,59.124586 C26.4805096,59.124586 0,32.6440764 0,2.84217094e-14 L118.249172,2.84217094e-14 Z M137.750828,194.005605 C137.750828,161.328917 164.198726,134.881019 196.875414,134.881019 C229.552102,134.881019 256,161.361529 256,194.005605 L137.750828,194.005605 Z M137.750828,142.740382 L137.750828,0 L256,0 L137.750828,142.740382 Z" | ||
fill="#03363D" | ||
></path> | ||
</g> | ||
</g> | ||
</svg> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"name": "@typebot.io/zendesk-block", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "index.ts", | ||
"keywords": [], | ||
"license": "AGPL-3.0-or-later", | ||
"devDependencies": { | ||
"@typebot.io/forge": "workspace:*", | ||
"@typebot.io/tsconfig": "workspace:*", | ||
"@types/react": "18.2.15", | ||
"typescript": "5.4.5", | ||
"@typebot.io/lib": "workspace:*", | ||
"@types/jsonwebtoken": "9.0.2" | ||
}, | ||
"dependencies": { | ||
"jsonwebtoken": "9.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Do not edit this file manually | ||
import { parseBlockCredentials, parseBlockSchema } from '@typebot.io/forge' | ||
import { zendeskBlock } from '.' | ||
import { auth } from './auth' | ||
|
||
export const zendeskBlockSchema = parseBlockSchema(zendeskBlock) | ||
export const zendeskCredentialsSchema = parseBlockCredentials( | ||
zendeskBlock.id, | ||
auth.schema | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"extends": "@typebot.io/tsconfig/base.json", | ||
"include": ["**/*.ts", "**/*.tsx"], | ||
"exclude": ["node_modules"], | ||
"compilerOptions": { | ||
"lib": ["ESNext", "DOM"], | ||
"noEmit": true, | ||
"jsx": "preserve", | ||
"jsxImportSource": "react" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found https://developer.zendesk.com/documentation/zendesk-web-widget-sdks/sdks/web/enabling_auth_visitors/#email-verification
So I guess the Email Is Verified field is useless here. We just need to tell the user to make sure the email was verified priori to providing it to Typebot. We could put that in a moreInfoTooltip for the email field
Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally thought the same, however, because open web widget is a client side action, that would lead to exposing the secrets used to create the JWT token on the client which would be highly insecure, no?
Email Verified is used in the JWT signing process. It's possible and valid to use verified and unverified emails when launching the web widget however as you may be dealing with new customers as well as existing, verified customers so we need to support verified and unverified emails. What verification does is that it tells the agent on the other end of the chat that the customer is known.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@baptisteArno what are your thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able for that action to define a server run function AND and a web function. The server function will first be executed.
But Zendesk is saying that if we provide Email without the email_verified field set to true then it will completely ignore the Email. So my question is what is the point to provide the email_verified field on Typebot. Let's make it always true and document the fact that the creator of the bot verifies the user email before providing it to Zendesk block
Or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see so, would the run block for openWebWidget look like this then? How do I pass the token from the server side auth function to the client openWebWidget function as it doesn't appear that variables are available to the client functions?
run: { server: async ({ credentials: { conversationsSecretKey, conversationsKeyId }, options: { userId, name, email, isEmailVerified, tokenVariableId }, variables, }) => { if (!email || email.length === 0 || !userId || userId.length === 0 || !name || name.length === 0 || conversationsSecretKey === undefined || conversationsKeyId === undefined || tokenVariableId === undefined ) return variables.set(tokenVariableId, sign({ scope: 'user', external_id: userId, name: name, email: email, email_verified: "true" }, conversationsSecretKey, { algorithm: "HS256", keyid: conversationsKeyId })); }, web: { parseFunction: ({ options }) => { return { args: { isAuthEnabled: options.isAuthEnabled ? options.isAuthEnabled?.toString() : "false", token: options.token ?? null, key: options.key ?? null }, content: parseOpenMessenger() } } }, },
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact parseFunction is executed on the server so you are right it should have access to variables, credentials etc... And you won't even have to declare a server run function. Let me push an update, will let you know once you can merge main into this branch 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: f613ce3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NICE!! Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, have removed the auth action, updated the openWebWidget action to generate the token. Looks good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and email_verified is set to true now