Snippet Installation using Signed Metadata with JWT

Important: This functionality must be enabled by a Pendo representative. Please reach out to support@pendo.io to request access.

Overview

With a typical snippet installation, the client passes metadata directly to the Pendo agent as a JSON object. All data exchanged between the agent in your application and Pendo is encrypted and transferred using Security Sockets Layer (SSL) protocol. Some industries require additional reassurance that metadata was not tampered with in-flight. Signed metadata is used to add a JSON web token (JWT) to your metadata and validate that it was not altered and did not originate from a source other than your installed agent. This is optional and not necessary for most installations. It adds additional complexity and may result in data loss if implemented incorrectly.

When using signed metadata in conjunction with the snippet installation, metadata passed to the Pendo agent must be contained in a signed token used to verify the integrity of the claims contained within it. This will not 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.

This is not 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. And, like a hotel key, when your stay has ended, you're simply left with a useless piece of plastic. The token doesn't do anything after it's expired.

 

Requirements

  • Active signed metadata access
  • Subscription admin access
  • Engineer who can modify your installed Pendo snippet

Configuring your application to accept signed metadata

Signed metadata must be active for your subscription for Advanced Security settings to be visible. Contact your Pendo representative if Advanced Security isn't available. "Use signed metadata" must be enabled for your subscription to accept data with JWT. If this setting is not enabled and you attempt to send signed metadata, it will be dropped.

 

1. Navigate to Subscription Settings > App Details > Install Settings.

 

2. Click Enable to accept signed metadata.

EnableSM.png

 

3. Update your snippet installation to transmit signed metadata. Do not complete the following steps until you are sending signed metadata.

  • If “Use signed metadata” is enabled, then we will accept either metadata with or without JWT.  
  • If “Only allow signed metadata” is enabled, we will only process events that have a verified signed JWT.
  • If “Use signed metadata” is disabled, we will not accept events with JWT. 

 

4. When your install snippet is updated and transmitting signed metadata, enable Only allow signed metadata.

OnlyAllowSM.png

 

5. Confirm that you want to only allow signed metadata. This will drop all events without signed metadata, as intended. Dropped data cannot be recovered.

ConfirmSMSettings.png

 

Generate key

This key is used to sign your metadata. You can create up to five keys. When set up is complete, your subscription will only accept data that's transmitted with one of your keys.

 

1. Navigate to the Active Keys table in Install Settings and click Generate Key.

NoActiveKeys.png

 

2. Enter a description to help you identify your keys later. Click Create to add a new key.

GenerateKey.png

 

3. The key is now available in the Active Keys table. Keys are hidden by default. Click Show to see the key.

ActiveKeysTable.png

 

Update Pendo snippet installation

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. There are many libraries out there that can be used to generate and sign JWTs.

There are a couple requirements to keep in mind when generating the JWT.

  • 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 "visitor" or "account", not contained within one of those sections. The value is not 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 is not signed with this algorithm, Pendo will not be able to verify the signature and the events will not be processed.

To send signed metadata, the client application must create a JWT to contain the metadata and use the generated key to sign it. Once the signed JWT is generated, the JWT and the key ID are sent to the Pendo agent instead of sending the metadata as a raw JSON body. You can send the JWT and key ID by including them in the Pendo snippet for your application as part of the pendo.initialize call. The JSON object passed to initialize must have both jwt and signingKeyName properties.

Any additional configuration you would like can be included alongside the jwt and signingKeyName properties.

 

Snippet example with JWT

jwt = JWT.sign({

   visitor:{
        id:             'VISITOR-UNIQUE-ID' // Required if user is logged in, must be a string
        // 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
        // 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
)

 

The agent includes the JWT with key ID when sending events for processing. Pendo will verify that the JWT has not been tampered with and will not process any events that are sent with an invalid JWT.

 

Exchanging and Revoking the JWT Secret Key

To revoke a previously used JWT secret key, a new key should be generated on the Install Settings page. Once the new key is properly inserted, the previous key should be revoked.

Warning: If an active key is revoked before the snippet is updated with the new key, data will not be processed until the JWT sent to Pendo is signed with the new key.

To revoke a key, click the Revoke Key icon when hovering over the key, then accept the confirmation to revoke the key permanently. This cannot be undone.

Screen_Shot_2020-04-06_at_3.09.51_PM.png

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

Additional Configurations

Can I use signed metadata and track 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 installation. Anonymous visitors should 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'
})

Identifying anonymous visitors
If you identify visitors with their unique visitor ID after initializing with an anonymous ID, call pendo.UpdateOptions(...) and update metadata as needed. This function works the same as a conventional Pendo installation.

 

Clear user metadata on log out

It is a best practice to clear the stored user metadata at the end of the session. This is encouraged if multiple users use the same computer and is highly recommended if multiple anonymous visitors use the same computer. If the stored metadata isn’t cleared, another user who should be identified as a new anonymous user may be incidentally identified using the stored metadata and their behavior will be attributed to the previously identified visitor.

This can be resolved by calling pendo.clearSession() in your app when the user logs out or before the next user is identified, for example on a login screen. This is particularly important on a login screen that loads when an expired cookie is detected to catch user sessions that ended when the browser was closed and did not log out or time out as expected.

 

Does signed metadata help prevent replay attacks?

Pendo will drop any duplicate events it receives, preventing malicious users from replaying the same event over and over. Signed metadata using JWT does not support the “jti” claim, commonly known as a way to prevent replay attacks. A signed metadata JWT will remain valid as long as the signature is valid. Revoking and exchanging tokens on a regular basis is the best way to prevent long lived JWT tokens from being exploited if compromised.