JSON Web Tokens (JWT) Authentication
JWTs are short-lived, signed tokens used to securely authenticate and authorize connections from Courier SDKs to the Courier backend. They are the recommended authentication method in all cases. JWT generation requires a private key which is unique to your Courier workspace, and should only be accessed in secure environments such as your backend server. A typical production JWT generation flow might look like this:
Your app calls your backend
When your app needs to authenticate a user, your app
should make a request to your own backend (ex.
GET https://my-awesome-app.com/api/generate-courier-jwt).Your backend calls Courier
In your backend, use your Courier API Key to call the Courier Issue Token Endpoint and generate a JWT for the user.
Testing JWTs in Development
To quickly get up and running with JWTs in development, you can use cURL to call the Courier Issue Token Endpoint directly.Client Key and HMAC Authentication (Deprecated)
HMAC authentication adds a hash-based code to the request to verify its authenticity. For requests to the Courier backend, the HMAC is a hash of theuserId and your Courier API Key.
hmac.ts
Troubleshooting
JWT errors
Messages not loading (401 or empty Inbox) The most common cause is an expired token or missing scopes. Decode your JWT at jwt.io and check:exp— is the expiration in the future? Tokens with shortexpires_invalues can silently expire between page loads. If your users keep sessions open for long periods, add a refresh mechanism that requests a new token before the current one expires.scope— does it includeinbox:read:messagesandinbox:write:events? Without these, the SDK connects successfully but returns no messages. A minimal working scope string looks like:
read:preferences write:preferences if you use the embedded Preferences editor, and write:user-tokens if you sync push tokens from the client.
Cross-channel read sync
When cross-channel sync is enabled, reading a message in one channel (for example, opening an email) marks the corresponding Inbox message as read. This relies on a tracking pixel embedded in the email body. If your users’ email clients block tracking pixels (common in corporate environments with strict privacy policies), the read event never fires and the Inbox message stays unread. There is no workaround on the email side; you can call the Messages API to mark messages read programmatically if needed. To disable cross-channel sync entirely, enableoptOutOfInboxSync in your Courier Inbox provider settings. This keeps Inbox message state independent of other channels.