Note: This functionality must be enabled by a Pendo representative. Contact Pendo Support to request access.
With a typical mobile application installation, the mobile device passes metadata directly to the Pendo servers 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 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 specific mobile device.
Note: 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 mobile installation, metadata passed to the Pendo servers 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 that 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 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 has expired.
Requirements
- Active signed metadata access
- Subscription admin access
- An engineer who can modify the mobile application containing the Pendo SDK
- An engineer who can generate JSON web tokens (JWT) and send them to devices containing the mobile application
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. You must enable Use signed metadata 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.
- Navigate to Subscription Settings > View App Details > Install Settings.
- Click Enable to accept signed metadata.
- Update your mobile 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.
- When your mobile installation is updated and successfully transmitting signed metadata, enable Only allow signed metadata.
- Confirm that you want to only allow signed metadata. This drops all events without signed metadata, as intended. Dropped data cannot be recovered.
Generate Key
This key is used to sign your metadata. You can create up to five keys. When setup is complete, your subscription only accepts data that is transmitted with one of your keys.
- Navigate to the Active Keys table in Install Settings and click Generate Key.
- Enter a description to help you identify your keys later. Click Create to add a new key.
- The key is now available in the Active Keys table. Keys are hidden by default. Click Show to see the key.
Pendo mobile 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.
Example of a JWT generation on your server side:
jwt = JWT.sign({
visitor:{
id: 'VISITOR-UNIQUE-ID' // Required field, 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 field, must be a string
// 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' // Generated key
)
To send signed metadata, the mobile application must obtain the JWT and key ID from your server side. The JWT containing the metadata must be signed with the generated key corresponding to the key ID. Once the signed JWT is generated and obtained by the mobile device, the JWT and the key ID are sent to Pendo’s servers instead of sending the metadata as a raw JSON body. Pendo will verify that the JWT has not been tampered with and will not process any events that are sent with an invalid JWT. You can send the JWT and key ID in your mobile application by passing them to the Pendo.startSession call as the jwt and signingKeyName argument properties. The call to Pendo.startSession should be called after calling Pendo.setup.
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.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().startSession(jwt, signingKeyName);
Exchange and Revoke the JWT Secret Key
To revoke a previously used JWT secret key, a new key must be generated on the Install Settings page. Once the new key is properly inserted, the previous key is revoked.
Warning: If an active key is revoked before the snippet is updated with the new key, data is not 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.
You can find a log of all Revoked Keys underneath the Active Keys section.
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.startSession is called with an empty string assigned to the visitor ID as part of the metadata. 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 an anonymous visitor JWT generated on your server side:
const jwt = JWT.sign({
nonce: "abcdefg78910xyz",
visitor: {
id: "SESSION-VISITOR-UNIQUE-ID",
existingVisitorField: "some value"
},
account: {
id: "",
otherAccountField: "some other value"
}
},
'SECRET KEY'
);
Identifying anonymous visitors
If you identify visitors with their unique visitor ID after initializing with an anonymous ID, call Pendo.startSession again with a JWT containing the updated visitor ID and metadata as needed. This function works the same as a conventional Pendo installation.
Can I Update Visitor Data During a Session?
Visitor data can be accumulated / updated during the session by calling Pendo.setVisitorData and / or Pendo.setAccountData. When using these calls pass a JWT and key ID similarly to the Pendo.startSession. However, the JWT payload with these calls must meet the following criteria:
- The payload must contain either a visitor property or an account property but not both.
- The ID value supplied for either the visitor or account must be identical to the ID value used in the JWT passed when calling the Pendo.startSession.
Example of an a JWT generated to update the visitor data:
const jwt = JWT.sign({
nonce: "abcdefg78910xyz",
visitor: {
id: "SESSION-VISITOR-UNIQUE-ID",
newVisitorField: "new value",
existingVisitorField: "updated value"
}
},
'SECRET KEY'
);
Example of an a JWT generated to update the account data:
const jwt = JWT.sign({
nonce: "abcdefg78910xyz",
account: {
id: "SESSION-ACCOUNT-UNIQUE-ID",
newAccountField: "new value",
existingAccountField: "updated value"
}
},
'SECRET KEY'
);
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.