Skip to main content

Support for logged-in users

Prerequisite

This guide assumes you've set up the chat UI for anonymous/logged-out users. If you haven't, please head over to support for logged-out users first.

With just logged-out support, all your website visitors will need to go through an email-based authentication process in order to verify who they are. This flow captures and verifies their email address, as well as creating a new customer in your Plain workspace.

However, if one of your users is already logged in on your website, you don't want them to go through authentication again. You already know their email address and personal details!

The Chat UI can be configured to help you get your users' details into Plain, which means:

  • Your logged-in users can start typing right away when they open the chat.
  • They will show up as a customer in your Plain workspace with the correct name and email.

In the logged-in flow:

  • The chat UI requests a JWT from your backend. Your backend generates a JWT containing the customer details, signing it with a private key
  • The chat UI exchanges the JWT for a session token with Plain

The sequence of this flow is shown here:

JWT exchange

There are two prerequisites before we are able to configure the Chat UI to support logged-in users:

  1. Generating a key pair
  2. An API to create customer JWTs

1. Generating a key pairโ€‹

info

This assumes that you are working on macOS. If you are not, please get in touch with us at help@plain.com, and we can provide alternative methods to generate key pairs.

A private/public key pair is required to sign JWTs (on your server) and verify them (on Plains). This is a security measure to prevent bad actors from impersonating your users.

Let's create a key pair and add the public key to your workspace:

  1. Run the following in your terminal and follow the prompts:
    (The source code of this script is here: https://github.com/team-plain/generate-rsa-key-script)
bash <(curl -fsSL https://raw.githubusercontent.com/team-plain/generate-rsa-key-script/main/generate_rsa_key_pairs.sh)
  1. After the script completed it should have created a private key ending in .key.pem and a public key ending in .key.pem.pub.

  2. Go to your workspace at app.plain.com and open Settings -> Apps. Choose the one you created earlier. Then click on "Add Public Key" App key list App key details

  3. Choose a name for the public key (this is not shown publicly, so choose something that makes sense to you), paste its contents and click on "Create public key" App key details

  4. After that, you should land back on the workspace app page. It means the public key has been added successfully. App key details

2. Creating customer JWTsโ€‹

info

A customer JWT is the mechanism by which your users can authenticate as customers on Plain.

Customer JWTs must be created and signed on your servers. Not doing so would mean exposing your private key, so anyone could impersonate your customers while getting in touch with Plain.

The JWT payload must conform to the following schema:

customer_jwt_schema.json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"fullName": {
"type": "string",
"description": "The customer full name"
},
"shortName": {
"type": "string",
"description": "The customer first name"
},
"email": {
"type": "object",
"properties": {
"email": {
"type": "string",
"description": "The customer email"
},
"isVerified": {
"type": "boolean",
"description": "Whether or not you have already established that the user has access to the email address they've provided you; for example if they've already verified their email on your app or website."
}
},
"required": [
"email",
"isVerified"
]
},
"externalId": {
"type": "string",
"description": "Your customer's id in your own systems. If provided, this is what is used to identify customers. If Plain receives a customer with the same externalId as one we've seen before, we'll update any details that have changed. If not, we'll create a new customer."
}
},
"required": [
"fullName",
"email",
"externalId"
]
}

How you sign a JWT depends on the programming language you use in your backend.

Here is an example of how you could do this in NodeJS. The code assumes your private key is exposed as an environment variable PRIVATE_KEY with no passphrase.

var jwt = require('jsonwebtoken');

const customer = {
fullName: "Garnett Hermann",
shortName: "Garnett",
email: {
email: "garnett.hermann@aol.com",
isVerified: false
},
externalId: "your_id",
};

const token = jwt.sign(customer, process.env.PRIVATE_KEY, {
algorithm: "RS256",
expiresIn: "1h"
});

You can find a similar library for any language on https://jwt.io/libraries.

The way you expose the JWT signing to your website is up to you. You can embed the resulting customer JWT in the page, serve it from an API, etc. It doesn't really matter as long as the JWT is generated server-side and the private key is kept secret.

In this tutorial, we'll assume that we're exposing it through an API endpoint: POST /api/get-customer-jwt.

tip

You can see a sample endpoint implementation on our NextJS example app.

Once you have a way to create customer JWTs and expose them, you'll need to configure the chat UI to use the JWT. This can be done either via a script tag or the React npm package.

Script tagโ€‹

If you already set up the script tag for logged-out users, you can update your code to include the highlighted part below by invoking the set-customer action. Alternatively, copy and paste the whole code fragment (replace APP_KEY with the key you obtained on getting an app key)

<script>
window.$plain = window.$plain || [];

typeof plain === 'undefined' && (plain = function () { $plain.push(arguments); });

plain("init", {
appKey: "APP_KEY"
});

plain('set-customer', {
type: 'logged-in',
getCustomerJwt: () => {
return fetch('/api/get-customer-jwt/', {method: 'POST'})
.then(res => res.json())
.then(res => res.plain_customer_jwt);
}
});
</script>
<script async src="<https://customer-chat.cdn-plain.com/latest/customerChat.js>"></script>

The most important part here is the getCustomerJwt function. This function must return a valid customer JWT.

In this case, the function will be called when the page loads, querying your endpoint /api/get-customer-jwt/ and obtaining the customer JWT back. This JWT is then sent to Plain and exchanged for a token, which is then used for the duration of the chat session.

When the user logs out, it is important you also log them out of Plain. You can do this by invoking the following snippet on log out:

plain('set-customer', {
type: 'logged-out'
});

And you are all set. At this point your logged-in users will be able to send chat messages to you, and they will all show up as customers in your workspace in the Support App.

npm packageโ€‹

tip

Did you know we have a sample NextJS app showcasing how to use the React npm package?

With full logged-in user support, including an example on how to use the usePlain hook to get the number of unread notifications for a user. Check it out at team-plain/example-nextjs.

Besides the appKey prop, the PlainProvider also takes a prop called customer.

The customer prop can be used to specify the current customer (your current user), and show them the correct conversations with you.

To specify the logged in customer you have to provide the following customer prop to the PlainProvider (replace APP_KEY with the key you obtained on getting an app key):

import React from 'react';
import { PlainProvider, Chat } from '@team-plain/react-chat-ui';

const customer = {
type: 'logged-in',
getCustomerJwt: () => {
return fetch('/api/get-customer-jwt', { method: 'POST' })
.then(res => res.json())
.then(res => res.plain_customer_jwt);

}
}

function App() {
return (
<PlainProvider appKey="APP_KEY" customer={customer}>
<h1>Your app</h1>
<Chat/>
</PlainProvider>
);
}

ReactDOM.render(<App/>);

The most important part here is the getCustomerJwt function. This function must return a valid customer JWT.

The chat UI will call this function, querying your endpoint /api/get-customer-jwt/ and obtaining the customer JWT back. This JWT is then sent to Plain and exchanged for a token, which is then used for the duration of the chat session.

When the user logs out it is important you also log them out of Plain. You can do this using the usePlain hook:

const { logout } = usePlain();
<button onClick={logout}>
Logout
</button>

If you run your app now you should be able to chat in the <Chat/> component and see customer messages show up in your workspace in the Support App ๐ŸŽ‰


If you have any problems, please get in touch with us by email on help@plain.com, and we will be happy to help.