Managed Consent Database
When a user has signed in on your application, your backend will serve a token to your frontend, which allows Transcend's SDK to save this authenticated user's consent preferences.
The token you'll serve is a JSON Web Token (JWT) containing a unique identifier for this user.
The identifier is encrypted on your backend server, placed in a JWT, and signed by your backend server. The encryption and signing keys can be found in the Admin Dashboard. More info about these keys can be found here.
The encryption algorithm is AES-KWP. The signing algorithm is HMAC-SHA-384.
import * as crypto from 'crypto';import * as jwt from 'jsonwebtoken';function createConsentToken(userId: string,base64EncryptionKey: string,base64SigningKey: string): string {// Read on for where to find these keysconst signingKey = Buffer.from(base64SigningKey, 'base64');const encryptionKey = Buffer.from(base64EncryptionKey, 'base64');// NIST's AES-KWP implementation { aes 48 } - see https://tools.ietf.org/html/rfc5649const encryptionAlgorithm = 'id-aes256-wrap-pad';// Initial Value for AES-KWP integrity check - see https://tools.ietf.org/html/rfc5649#section-3const iv = Buffer.from('A65959A6', 'hex');// Set up encryption algorithmconst cipher = crypto.createCipheriv(encryptionAlgorithm, encryptionKey, iv);// Encrypt the userId and base64-encode the resultconst encryptedIdentifier = Buffer.concat([cipher.update(userId),cipher.final(),]).toString('base64');// Create the JWT contentconst jwtPayload = {encryptedIdentifier,};// Create a JSON web token and HMAC it with SHA-384const consentToken = jwt.sign(jwtPayload, signingKey, {algorithm: 'HS384',});return consentToken;}
N.B. pip install cryptography pyjwt
import base64import jwtfrom cryptography.hazmat.primitives.keywrap import aes_key_wrap_with_paddingdef create_consent_token(user_id: str, base64_encryption_key: str, base64_signing_key: str) -> str:# Read on for where to find these keysencryption_key = base64.b64decode(base64_encryption_key)signing_key = base64.b64decode(base64_signing_key)# encode user_id as bytesuser_id_bytes = str.encode(user_id)# NIST's AES-KWP implementation { aes 48 } - see https://tools.ietf.org/html/rfc5649encrypted_identifier = aes_key_wrap_with_padding(encryption_key, user_id_bytes)# base64-encode the resultbase64_encrypted_identifier = base64.b64encode(encrypted_identifier)# Create the JWT contentjwt_payload = { 'encryptedIdentifier': base64_encrypted_identifier.decode() }# Create a JSON web token and HMAC it with SHA-384consent_token = jwt.encode(jwt_payload, signing_key, algorithm="HS384")return consent_token
Your server will generate the token and return it to the frontend (likely as part of the response payload for the login flow):
// When a user has authenticatedconst consentToken = createConsentToken(userId,base64EncryptionKey,base64SigningKey);return {status: 200,body: {user: authenticatedUserData,consentToken,}}
On the frontend, you will then pass this token to Transcend:
// Authenticate the user to airgap, and sync their consent with Transcend's Managed Consent Databaseairgap.sync({ auth: consentToken });
The keys above, encryptionKey
and signingKey
, can be retrieved from the Admin Dashboard, under the "Managed Consent Database" section on the Developer Settings page.
- Toggle "on" the Managed Consent Database feature (see screenshot)
- Click on View Encryption Key to see the
encryptionKey
in the code example above. Save the contents somewhere safe! - Click on View JWT Signing Key to see the
signingKey
in the code example above. Again, please save the contents somewhere safe!
- Make sure Reporting Only mode is off
- Your domain is included in the Domains List (e.g.
localhost:3033
if you're using the backend-consent-example) - Navigate to Regional Experiences and make sure that you are in a region with an experience defined. (e.g. if you are in New York, set an experience using either the region of New York or the New York time zone (or both) and add a purpose (e.g. Advertising) to it.)
- If you haven't already, copy the HTML Snippet into the page you want to test this on (using the Test bundle)
Now that you've collected the user consent from the web, you may need to look up their consent record as part of executing backend data processes. This can be easily done using our Sombra API.
Endpoint reference: Query User Consent
Your backend server may need to gate tracking/data-processing logic based on the user consent preferences. An example of how to do so for user with email 'foo@example.com':
const request = require('request');const result = request.post('{{yourOrganizationSombraURL}}/v1/consent-preferences',{headers: {authorization: 'Bearer {{apiKey}}','x-sombra-authorization': 'Bearer {{sombraApiKey}}','content-type': 'application/json',},body: {filterBy: {identifiers: 'foo@example.com',// grab this value from the Admin Dashboard > Consent > Developer SettingsconsentManagerId: 'ee1a0845-694e-4820-9d51-50c7d0a23467',},},json: true,});const consentPreference = result.nodes[0];// May be undefined/empty list if the user has never given consentif (consentPreference?.purposes?.Advertising) {// The user has given consent to Advertising, perform some custom logic...}if (consentPreferences?.purposes?.Functional !== false) {// The user has NOT explicitly opted out of Functional tracking purpose, perform some custom logic...}
A common scenario: your company uploads a list of users to Facebook once a week, and you need to filter this list to exclude users who have opted out of targeted advertising. Here's an example of how you might do so:
const request = require('request');const { nodes: userConsentPreferences } = request.post('{{yourOrganizationSombraURL}}/v1/consent-preferences',{headers: {authorization: 'Bearer {{apiKey}}','x-sombra-authorization': 'Bearer {{sombraApiKey}}','content-type': 'application/json',},body: {filterBy: {identifiers: userIdentifiers,// grab this value from the Admin Dashboard > Consent > Developer SettingsconsentManagerId: 'ee1a0845-694e-4820-9d51-50c7d0a23467',},},json: true,});const usersToUpload = userIdentifiers.filter((identifier) =>userConsentPreferences.find((data) =>data.userId === identifier &&// This logic makes sure that the user has not explicitly opted out// You may also write your own logic here to check for explicit consent (opt-in) as welldata.purposes?.Advertising !== false &&data.purposes?.SaleOfInfo !== false));// Now you can safely upload `usersToUpload`