Send signed metadata with JWT

Last updated:

Important: The ability to install using signed metadata with JWT must be enabled by a Pendo representative. Contact Pendo Support to request access.

With a typical Pendo installation, your application passes metadata to the Pendo sever as a JSON object. All data exchanged between your application and Pendo is encrypted and transferred using Security Sockets Layer (SSL) protocol.

Some industries require additional reassurance that metadata isn't tampered with in-flight. Pendo signed metadata requires the use of JSON Web Tokens (JWT). JWT is an open, industry standard method (RFC 7519) for representing claims securely between two parties.

This article covers the process for installing Pendo using signed metadata with JWT. Broadly, this involves the following steps:

  1. Enable signed metadata with JWT
  2. Generate a key to sign your metadata
  3. Start sending signed metadata
  4. Verify that you're sending signed metadata
  5. Enforce signed metadata only

JSON web token (JWT) overview

JSON web token (JWT) is an open standard that defines a compact and self-contained way to securely transmit information between parties as a JSON object.

Signed metadata is used to add a JWT to your metadata to validate that it wasn't altered and didn't originate from a source other than your application. This is optional and unnecessary for most installations. It adds additional complexity and might result in data loss if implemented incorrectly.

When using signed metadata in conjunction with the Pendo install script or SDK mobile integration, metadata passed to Pendo must be contained in a signed token used to verify the integrity of the claims contained within it. This doesn't hide the claims from other parties. This is addressed with standard data encryption, but the signature is used to verify the message wasn’t changed along the way.

JWT isn't encryption. Think of it as a hotel key. You register at the front desk and they give you a plastic electronic key (or token) with which you can access your room, the pool, and the garage. But you can't open other people's rooms or go into the manager's office. You can only access your rooms using your key and nobody can else can access your rooms without your key. Like a hotel key, when your stay has ended, the token doesn't do anything after it's expired.

Prerequisites

You must have the following to install using signed metadata using JWT:

  • Active signed metadata access for your subscription to install with JWT. This is a paid feature that is turned off by default and must be enabled by a Pendo representative.
  • Admin user access to your Pendo subscription.
  • Engineering resource to modify your Pendo installation code, generate JSON web tokens, and send them. 

For a smooth installation with JWT, we recommend first installing Pendo without signed metadata:

Step 1. Enable signed metadata with JWT

For your application to accept data with JWT, you must first enable Use signed metadata in your application's Install Settings page, under Advanced Security. If this setting isn't enabled and you attempt to send signed metadata, all data from these sessions are dropped.

  1. Navigate to Settings > Subscription Settings.

  2. Open the Applications tab.

  3. Find and open the relevant app from your Applications list.

  4. Open the Install Settings tab.
  5. Select Enable under Advanced Security to accept signed metadata.
    • For web implementation, this is found under Customize your snippet.

      EnableSM.png
    • For mobile implementation, this is found under Customize your SDK.

      Screen_Shot_2022-02-17_at_12.42.52.png

Note: If you can't see Advanced Security settings in your application's Install Settings page, contact your Pendo representative to enable signed metadata for your subscription. For more information, see Prerequisites.

After you've turned on Use signed metadata, another option appears: Only allow signed metadata. This is greyed-out until you generate at least one key to sign your metadata. After creating a key, don't enable Only allow signed metadata until you verify that you're sending events with signed metadata, as outlined in Step 4. Verify that you're sending events with signed metadata

Step 2. Generate a key to sign your metadata

JWT installation requires all requests to be signed using your JWT shared secret, otherwise data is dropped. 

After enabling signed metadata with JWT for your subscription, you need a key to sign your metadata. This key is different from the API key that appears in App Details > Basic settings. The API key connects Pendo to your application.

One active key is typically sufficient but you can have up to five active keys at a time for each application.

  1. From Install Settings, go to the Active Keys table and select + Generate Key.
  2. Enter a meaningful description for your key.
  3. Select Create. The key is now available in the Active Keys table.

Keys are hidden by default. Select Show to see the key.

Step 3. Start sending signed metadata

Sending signed metadata to Pendo requires technical or engineering resource to create JWTs that hold your metadata and to send them to Pendo. If you haven't already, we recommend that you first install Pendo without metadata before continuing.

You mustn't create or sign JWTs directly in your application code. To keep the secret key safe, known only to you and Pendo, you must create the signed JWT on your server-side and pass it to your application, together with the signing-key name, before calling the initialize (for web) or startSession (for mobile) method.

Generate signed JWTs

There are many libraries you can use to generate and sign JWTs. When you generate signed JWTs required to start sessions with Pendo, there are a few considerations:

  • JWT must be signed with the generated key corresponding to the key ID. 
  • The JWT payload must contain both the visitor and account elements, each with an id property and value. 
  • Visitor and Account IDs must be passed as strings for JWT installs. To generate an anonymous visitor, use an empty string as the value of the id property of the visitor element. The account id property may be set to an empty string as well. Additional visitor and account properties are optional.
  • A nonce property must be included in the claims. The nonce is a string randomly generated by the client and must be at the top level in the JSON as a sibling property to a visitor or account, not contained within one of those sections. The value isn't explicitly validated, but a value is required. Including a random nonce helps ensure that tokens always appear different even if they contain the same claims.
  • The HMAC SHA-256 algorithm should be used when signing the JWT. If the JWT isn't signed with this algorithm, Pendo can't verify the signature and the events aren't processed.
  • Any additional configuration you would like can be included inside the JWT metadata.
  • Historical metadata values must be included in every JWT.

See the proceeding pseudocode for generating a JWT to start a visitor session with Pendo:

jwt = JWT.sign({

   visitor:{
        id:             'VISITOR-UNIQUE-ID' // Required if user is logged in; must be a string. Pass an empty string for an anonymous visitor.
        // email:       // Recommended if using Pendo Feedback, or NPS Email
        // full_name:   // Recommended if using Pendo Feedback
        // role:        // Optional
        // You can add any additional visitor level key-values here,
        // as long as it's not one of the above reserved names.
    },

   account: {
        id:           'ACCOUNT-UNIQUE-ID' // Required if using Pendo Feedback; must be a string. Pass an empty string for an anonymous visitor.
        // name:         // Optional
        // is_paying:    // Recommended if using Pendo Feedback
        // monthly_value:// Recommended if using Pendo Feedback
        // planLevel:    // Optional
        // planPrice:    // Optional
        // creationDate: // Optional
        // You can add any additional account level key-values here,
        // as long as it's not one of the above reserved names.
    },

    nonce: 'randomly generated value'  // It should be different every time it is used
},
'JWT-SECRET-KEY' // Generate this key below
)

Warning: There should be no signing-key value in the code of your application. The JWTs that you're creating shouldn't be created on the application. They should be sent to the application from your server. You're application should be collected from the server, where the JWT is already signed.

Signed metadata with anonymous visitors

Anonymous visitors are automatically assigned a random string as a Visitor ID when pendo.initialize() is called without metadata assigned to the Visitor ID. This method of generating anonymous Visitor IDs is the same for a conventional or signed metadata Pendo implementation.

With signed metadata, anonymous visitors still use JWT when they pass event data to Pendo.

Example of the payload used to initialize anonymous visitors with JWT:

let payload = {
nonce: "abcdefg78910xyz",
visitor: { // notice there is no "id" field
otherVisitorField: "hi"
},
account: {
otherAccountField: "hello world"
}
}
const jwt = JWT.sign(payload, 'SECRET KEY');
pendo.initialize({
jwt: jwt,
signingKeyName: 'SIGNING KEY NAME'
})

Update your application installation code

To send signed metadata, your application must fetch your JWT and signing key name from your server and pass them on to Pendo when starting a session.

Web implementation

For a web implementation, you can send the JWT and key ID by including them in the Pendo install script for your application as part of the initialize method. The JSON object passed to initialize must have both jwt and signingKeyName properties.

Mobile implementation

For a mobile implementation, you can send the JWT and key ID by including them in your mobile SDK integration for your application as part of the startSession method. You must directly pass both jwt and signingKeyName properties to the startSession method.

Example of an android mobile device sending the JWT to Pendo (Java):

Pendo.setup(this, pendoAppKey, null, null);

String jwt = “JWT-SIGNED-TOKEN”; // obtained from your server

String signingKeyName = “SECRET-KEY-ID” // obtained from your server
Pendo.jwt.startSession(jwt, signingKeyName);

Example of an iOS mobile device sending the JWT to Pendo (Swift):

PendoManager.shared().setup(pendoAppKey, nil);

let jwt = “JWT-SIGNED-TOKEN”; // obtained from your server
let signingKeyName = “SECRET-KEY-ID” // obtained from your server
PendoManager.shared().jwt.startSession(jwt, signingKeyName);

Step 4. Verify that you're sending signed metadata

The following steps require you to know what visitor you're testing with. Typically, this involves signing in as a particular visitor to your application.

  1. Go Settings > Subscription Settings > Applications.
  2. Find and open your application.
  3. Open the Raw Events tab.
  4. Check for new data flowing into Pendo from the visitor that you're testing with.

Step 5. Enforce signed metadata only

When your install script is updated and transmitting signed metadata, you can enforce it to ensure that data from sessions without secure metadata are dropped going forward. Up until this step, only Use signed metadata is enabled, which means that we accept metadata with or without JWT.

When you enable Only allow signed metadata, we only process events that have a verified signed JWT. To enable this setting:

  1. From your application settings, open the Install Settings tab.
  2. Enable Only allow signed metadata under Advanced Security.
    • For web implementation, this is found under Customize your snippet.
    • For mobile implementation, this is found under Customize your SDK.
  3. Confirm that you want to only allow signed metadata by reviewing the checklist and entering "I understand" before selecting Enable Signed Metadata.

This drops all events without signed metadata, as intended. After the signed JWT is generated and obtained by the client or mobile device, the JWT and key ID are sent to Pendo's servers. Pendo checks the JWT against the secret key, known only to your server and Pendo's sever, to verify that it hasn't been tampered with. Pendo doesn't process any events that are sent with an invalid JWT. Dropped data can't be recovered.

Important: You could experience data loss if your public application is using Pendo without secure metadata or if mobile visitors haven't had time to update to an application version using JWTs and you attempt to enforce signed metadata using the instructions in this section.

Replay attacks 

Signed metadata using JWT doesn't support the “jti claim" (a unique identifier assigned to each JWT), typically used to prevent replay attacks. Instead, Pendo drops any duplicate events it receives, preventing malicious users from replaying the same event. Additionally, you can exchange and revoke the JWT secret key as a way of mitigating replay attacks

Exchange and revoke the JWT secret key

A signed metadata JWT remains valid as long as the signature is valid. Exchanging and revoking tokens on a regular basis is the best way to prevent long-lived JWTs from being exploited if compromised. This is relevant to replay attacks.

To exchange a previously used JWT secret key, generate a new key in the Install Settings page. For instructions, see Step 2. Generate a key to sign your metadata. You must start using the new key to sign your JWTs, replacing the key that you want to revoke. Before you can revoke the old key, you must update the key ID sent along to the JWT to the application. You can then revoke the old key.

Warning: If an active key is revoked before your JWT signing is updated with the new key, data isn't processed until the JWT sent to Pendo is signed with the new key.

To revoke a key, hover over the key in the Active Keys table and select the Revoke Key icon, then accept the confirmation to revoke the key permanently. This can't be undone.

Screen_Shot_2020-04-06_at_3.09.51_PM.png

You can find a log of Revoked Keys underneath the Active Keys section. Screen_Shot_2020-04-06_at_3.02.58_PM.png

 

Was this article helpful?
4 out of 7 found this helpful