â ïž This feature is in beta. To be added, reach out to security@intercom.io
If you have the Messenger installed on your site for logged in users, it's essential to secure it and prevent bad actors from impersonating your users or sending unauthorized data. â
On a Messenger that's not secure, someone could interact with your Intercom Messenger and spoof the identity of another user, by providing a known identifier like their email address or user_id. This allows an attacker to pose as a real user to your teammates, giving access to previous conversations and potentially sensitive data.
If you have a Messenger integration with logged in users, we strongly recommend you secure your Messenger.
What is a JSON web token (JWT)?
A JSON Web Token (JWT) is an industry standard way to sign data. It typically consists of three parts, separated by dots. A typical JWT looks like this: header.payload.signature.
The header specifies the token type (JWT) and the signing algorithm (e.g., HS256).
The payload contains claims about the user or session (e.g., user_id, email).
Finally, the signature ensures that the token hasnât been tampered with, using a secret or private key.
What are the benefits of securing the Messenger with JSON web tokens (JWTs)?
Secure user identity: Securing your messenger allows your teammates to be sure that the user they're talking to, is really that user.
Enhanced user data security: Securing your Messenger allows for the safe transmission of data attributes about your user through the Messenger API.
Reduced risk from stolen sessions: Securing your Messenger with JWTs allows you to set expiration for the token, significantly reducing the risk of data breaches that could occur if tokens are stolen from your userâs browser. By specifying a short expiration, the risk is lessened.
Safer Fin and AI workflows: Give your complex processes, Actions, and Workflows to Fin, even if they require trustworthy user information.
By securely transmitting user identity and data and enforcing token expiration, JWTs ensure your Intercom Messenger is in the most secure state it can be.
Customer experience
When using JWTs with the Intercom Messenger, the experience is as follows:
Your Messenger integration will boot your logged-in user user with an
Intercom('boot')
request containing a JWT, which includes any and all user data you wish to send to Intercom. The JWT's signature is generated using the Messenger secret key from your settings.Then, Intercom will supply the user with a session cookie in their browser. This cookie with a default duration of 7 days. The cookie will be used for its lifetime to authenticate the user and perform any updates to that user.
If the session expires, and no fresh JWT is sent, the user's session will end. The user will see a fresh Messenger as a logged-out website visitor. It will not contain their conversation history.
Once the Messenger is rebooted with
Intercom('boot')
and a valid JWT, the Messenger will identify the user and show the user their historical conversations and a new session. We will additionally merge any logged-out activity that occurred on the same device into that authenticated user's account.
If you wish for the life of the user's session cookie to be shorter than the default 7 days, you can specify the TTL of the cookie in milliseconds with the session_duration Messenger attribute.
Installation: Generating and sending JWTs
Step 1: Install the Messenger in your application
You can find the unique setup instructions for your workspace here. â
The main difference between an insecure Messenger setup and a secure setup is that you will include an additional intercomUserJwt field in your user requests and that will be used to identify and update the user.
You will see an option to add data attributes into your Javascript snippet. This governs which data you want to send to Intercom. Since you will be using JWTs for transmitting data to us, you should only include attributes here that you donât want to sign e.g: if you want to send some front-end specific data.
If you donât want to send any data outside the JWT, you can remove all data from your snippet except for the api_base and app_id. Your app_id is the unique identifier for your Intercom workspace.
Step 2: Start generating JWTs for your users
You can use industry standard JWT libraries to generate the token, using the Messenger API Secret as the secret key. Your secret key can be generated in your workspace's Messenger security settings.
Choose your back and front end frameworks to get relevant code examples for your installation.
Here is an example for Node.js:
If there are additional attributes you want to send about your users (e.g: price_plan or number_of_songs_added) you would add those into your JWT also. user_id is the only required field. Learn more about custom data attributes here.
When should I include the JWT?
You should send a JWT for every request where you are booting a user in the Messenger or trying to update data about them.
What expiry should I set?
Set a short expiry for your JWT, ensuring that it lives long enough for a full request to reach and be processed by us. Expiry is not a required field but strongly recommended to reduce risk of token replay.
Step 3: Add JWTs to your Messenger snippet
When launching the Messenger for a logged-in user, you can provide a signed JSON Web Token and assign it to the intercom_user_jwt attribute of the Messenger payload.
Example Client-Side Configuration
window.Intercom("boot", {
api_base: "https://api-iam.intercom.io",
app_id: "APP_ID_CODE",
intercom_user_jwt: <YOUR_USER_JWT_TOKEN>,
};
This JWT can contain any user data attributes you want to securely send for the user. Once a valid JWT is received for the user, a session cookie will be created in the userâs browser with a default duration of 7 days.
To control the TTL of the Messenger session cookie, you can set a maximum under Settings > Channels > Messenger > General > Keep your Messenger secure
Step 4: Ensure updates are disabled for your attributes
It is possible to enable insecure updates for data attributes for the Messenger API, which means that any update through the Messenger to update that attribute will succeed.
If you are sending some data securely in your JWT, you should ensure that you disable insecure Messenger updates for those attributes such that they are only updated via a valid JWT. Note: this toggle does not prevent you from collecting data directly from leads with a bot
We recommend you enable this toggle for any attribute youâre sending in your JWT.
Step 5: Shutdown user sessions on logout
Intercom allows you to put the Intercom Messenger on any public facing site that you own (your marketing site, your docs site, your developer hub, etc). In order to maintain continuity of conversations across all of these potentially different subdomains while your users are logged in, we set a cookie in your userâs browser. This cookie expires after one week.
Any user that uses a shared computer and browser with someone else will be able to see the most recently logged in userâs conversation history until the cookie expires. Because of this, itâs very important to properly shutdown Intercom when a userâs session on your app ends (via manually or automatically logging out).
Hereâs how to shutdown Intercom:
You will have already begun tracking your user via the Intercom JS snippet or the âbootâ method.
When your user logs out of Intercom (or is automatically logged out by your app), call Intercom('shutdown'); from our JavaScript API, to end the Intercom session and clear the cookie.
đ Final step: Enforce Messenger Security for your workspace
When your integration is properly sending JWTs for your users, you should enforce Messenger security by toggling it on in your Messenger settings. By doing this, Intercom will require that requests for your workspace users are secured with either a valid JWT or a valid user_hash.
Troubleshooting guidance
We have two tools to help you debug your installation, one way to see recent error logs and a token debugger.
Check your installation logs
On step 6 under Settings > Channels > Messenger > Security, you will see your installation logs. These will show all failure logs related to your JWT installation. Here you will see errors noting whether your JWTs are invalid, expired etc. You click on "View log" to see a full log including the request ID, timestamp, referer and user data. This can help you understand why your request failed and help you trace it back to your own app.
Common Error Messages
HTTP 400 - "user_hash and intercom_user_jwt cannot be provided simultaneously"
: The request included both a JWT and a user_hash. Customers should include either of these values, but not both.HTTP 400 - âMissing user_id in payloadâ
: All JWTs are expected to include user_id as part of the payload. If a customer considers âemailâ their primary identifier, they should put the email value into both the user_id and email fields in the payload.HTTP 400 - âInvalid intercom_user_jwt payloadâ
: The JWT payload is invalid. Customers should ensure the payload is well-formed, encoded, and signed with a SHA256 HMAC using the api_secret value as the signing secret.HTTP 400 - âIntercom_user_jwt expiredâ
: The JWT âexpâ is a timestamp in the past. Customers should provide an expiration date in the future.HTTP 400 - "Invalid intercom_user_jwt"
: Ensure you are properly booting a valid user.
JWT decoder
Our decoder tool also gives you a way to check a JSON web token. You can find it on the sidebar on the installation pages.
In the tool you can check one of your generated user JWTs for validity. Choose the relevant secret key you used to generate the JWT and click Decode.
Once decoded you can see the user details from your JWT's payload, the header and a note as to whether it's valid or invalid.
In this example I have used both an invalid secret and I'm not including the user_id field, both of which will cause a failure.
FAQs
Why is user_id required within the JWT?
We require that customers provide user_id as their primary identifier for their Users. Historically, weâve supported either user_id or email as potential identifiers for legacy reasons, but this has created significant product confusion in basic Identity Verification. We are being opinionated here. If the customer only has an Email to identify their users with, they can supply the email address in both the user_id and email attributes of the payload.
What should I set my expiration to?
You should send a new JWT each time the Messenger is booted, and so the lifetime of the token only needs to support the length of time between Messenger launches. Choose the minimum duration that is suitable for their applicationâs behavior. If the web page is often reloaded, the JWT should be short-lived, though we suggest a minimum of 5 minutes to prevent unexpected expiry issues.
Can I send both a user_hash and intercom_user_jwt?
No, we donât support sending both the user_hash and the intercom_user_jwt, as the `user_hash` should be superseded by JWTs. You can, however, alternate between sending user_hashes and/or intercom_user_jwt values, as some customers will need to do this as they migrate from user_hash to intercom_user_jwt
If you're currently using Identity Verification and sending user hashes, see this guide for changing your integration to send JWTs instead.
How can I check that my JWTs are valid and things are working?
See Troubleshooting section above.
How do I enforce the requirement for JWTs for my workspace?
You should enable the enforcement toggle in your Messenger settings.
What attributes should I protect?
All identifying attributes should be marked protected and sent securely in the JWT if possible. This includes, email, phone, and any account_ids the customer may store on the User record. You can find your attributes here.
Any attribute that you want Fin to use in a critical part of an Action or Workflow should be protected, to ensure a malicious user cannot override that value.
If you want to send data outside the JWT, you can do that as long as you have allowed Messenger updates but keep in mind that a user could update this field themselves.
window.intercomSettings = {
app_id: <APP_ID_CODE>,
intercom_user_jwt: <TOKEN>,
unsigned_data_attribute: 'data'
};
What if the session expires in the middle of the user doing something?
If there is activity within the Messenger from a user after the cookie expires, Intercom will issue a fresh short lived cookie of 1 hour to avoid negative impact to the user experience. To prevent any unintended effects to the user experience we recommend you choose a session duration of the cookie that matches that of your applicationâs session timeout.
What about my mobile Messenger?
We do not yet offer support for JWTs in the Mobile Messenger SDKs. This is coming soon.
What about Segment / Google Tag Manager / Shopify / Wordpress?
Not all integrations have been updated to send the intercom_user_jwt field yet, however if you can manually update your integration to send this field, it will work.
Why donât we require the full payload to be signed?
We allow for customers to send un-signed Attributes to support situations where they need to send low-fidelity data about the User, while the User is taking action in their application. If the customer doesnât need this capability, they can update all their User Data Attributes to be âprotected from Messenger updatesâ and only send the signed payload.
How do I manage and rotate my Messenger secret keys?
Your secret key can be generated in your workspace's Messenger security settings.
I've found a bug!
Please report bugs to security@intercom.io immediately.
Need more help? Get support from our Community Forum
Find answers and get help from Intercom Support and Community Experts