1- // ============================================================================
2- // UID2 Prebid.js Client-Server Integration Example - Server
3- // ============================================================================
4- // This server demonstrates how to generate UID2 tokens on the server side
5- // for use with Prebid.js in a client-server integration.
6- //
7- // Key responsibilities:
8- // 1. Accept user email from the front-end
9- // 2. Encrypt the email and send it to the UID2 API
10- // 3. Decrypt the UID2 token response
11- // 4. Return the token to the front-end for use with Prebid.js
12- // ============================================================================
13-
1+ // UID2 Prebid.js Client-Server Integration - Server
2+ // Generates UID2 tokens server-side for use with Prebid.js
143
154require ( 'dotenv' ) . config ( { path : '../../../.env' } ) ;
165
@@ -21,86 +10,52 @@ const crypto = require('crypto');
2110const app = express ( ) ;
2211const port = 3052 ;
2312
24- // UID2 API Configuration
25- // These values should be set via environment variables for security
13+ // UID2 API Configuration (set via .env file)
2614const uid2BaseUrl = process . env . UID2_BASE_URL || 'https://operator-integ.uidapi.com' ;
27- const uid2ApiKey = process . env . UID2_API_KEY ; // Your API Key from UID2 Portal
28- const uid2ClientSecret = process . env . UID2_CLIENT_SECRET ; // Your Client Secret from UID2 Portal
15+ const uid2ApiKey = process . env . UID2_API_KEY ;
16+ const uid2ClientSecret = process . env . UID2_CLIENT_SECRET ;
2917
30- // Encryption constants required by UID2 API
31- const ivLength = 12 ;
32- const nonceLength = 8 ;
33- const timestampLength = 8 ;
34- const encryptionAlgo = 'aes-256-gcm' ;
18+ // Encryption constants
19+ const ivLength = 12 ;
20+ const nonceLength = 8 ;
21+ const timestampLength = 8 ;
22+ const encryptionAlgo = 'aes-256-gcm' ;
3523
36- // Middleware setup
37- app . use ( express . static ( 'public' ) ) ;
38- app . use ( express . json ( ) ) ;
39- app . use ( express . urlencoded ( { extended : true } ) ) ;
24+ // Middleware
25+ app . use ( express . static ( 'public' ) ) ;
26+ app . use ( express . json ( ) ) ;
27+ app . use ( express . urlencoded ( { extended : true } ) ) ;
4028
4129// ============================================================================
42- // HELPER FUNCTIONS FOR ENCRYPTION/DECRYPTION
30+ // Encryption/Decryption Helpers
4331// ============================================================================
44- // The UID2 API requires all requests and responses to be encrypted for security.
45- // These functions handle the encryption/decryption process.
46-
47- /**
48- * Converts a Buffer to a base64-encoded string
49- * @param {Buffer } arrayBuffer - The buffer to convert
50- * @returns {string } Base64-encoded string
51- */
32+
5233function bufferToBase64 ( arrayBuffer ) {
5334 return Buffer . from ( arrayBuffer ) . toString ( 'base64' ) ;
5435}
5536
56- /**
57- * Converts a base64-encoded string back to a Buffer
58- * @param {string } base64 - The base64 string to convert
59- * @returns {Buffer } The decoded buffer
60- */
6137function base64ToBuffer ( base64 ) {
6238 return Buffer . from ( base64 , 'base64' ) ;
6339}
6440
65- /**
66- * Encrypts a message using AES-256-GCM encryption
67- * This is required by the UID2 API to protect user data in transit.
68- * @param {string|Buffer } message - The message to encrypt (typically user email)
69- * @param {string } base64Key - Your UID2 Client Secret (base64-encoded)
70- * @returns {Object } Object containing the ciphertext and initialization vector
71- */
41+ // Encrypts data using AES-256-GCM
7242function encryptRequest ( message , base64Key ) {
7343 const iv = crypto . randomBytes ( ivLength ) ;
7444 const cipher = crypto . createCipheriv ( encryptionAlgo , base64ToBuffer ( base64Key ) , iv ) ;
7545 const ciphertext = Buffer . concat ( [ cipher . update ( message ) , cipher . final ( ) , cipher . getAuthTag ( ) ] ) ;
76-
77- return { ciphertext : ciphertext , iv : iv } ;
46+ return { ciphertext, iv } ;
7847}
7948
80- /**
81- * Compares two byte arrays for equality
82- * Used to verify that the nonce in the response matches the request (prevents tampering)
83- * @param {Uint8Array } array1 - First array to compare
84- * @param {Uint8Array } array2 - Second array to compare
85- * @returns {boolean } True if arrays are equal, false otherwise
86- */
49+ // Compares two byte arrays
8750function isEqual ( array1 , array2 ) {
8851 for ( let i = 0 ; i < array1 . byteLength ; i ++ ) {
8952 if ( array1 [ i ] !== array2 [ i ] ) return false ;
9053 }
9154 return true ;
9255}
9356
94- /**
95- * Decrypts a response from the UID2 API
96- * Verifies the nonce to ensure the response hasn't been tampered with.
97- * @param {string } base64Response - The encrypted response from UID2 API
98- * @param {string } base64Key - Your UID2 Client Secret (base64-encoded)
99- * @param {Buffer } nonceInRequest - The nonce that was sent in the request
100- * @returns {Object } The decrypted JSON response containing the UID2 token
101- * @throws {Error } If the nonce doesn't match (indicates tampering)
102- */
103- function decrypt ( base64Response , base64Key , nonceInRequest ) {
57+ // Decrypts UID2 API response and verifies nonce
58+ function decrypt ( base64Response , base64Key , nonceInRequest ) {
10459 const responseBytes = base64ToBuffer ( base64Response ) ;
10560 const iv = responseBytes . subarray ( 0 , ivLength ) ;
10661
@@ -110,25 +65,23 @@ function decrypt(base64Response, base64Key, nonceInRequest) {
11065 const tag = responseBytes . subarray ( responseBytes . length - tagLength ) ;
11166 decipher . setAuthTag ( tag ) ;
11267
113- const decrypted = Buffer . concat ( [ decipher . update ( responseBytes . subarray ( ivLength , responseBytes . length - tagLength ) ) , decipher . final ( ) ] ) ;
68+ const decrypted = Buffer . concat ( [
69+ decipher . update ( responseBytes . subarray ( ivLength , responseBytes . length - tagLength ) ) ,
70+ decipher . final ( )
71+ ] ) ;
11472
73+ // Verify nonce matches
11574 const nonceInResponse = decrypted . subarray ( timestampLength , timestampLength + nonceLength ) ;
11675 if ( ! isEqual ( nonceInRequest , new Uint8Array ( nonceInResponse ) ) ) {
117- throw new Error ( 'Nonce in request does not match nonce in response ' ) ;
76+ throw new Error ( 'Nonce mismatch ' ) ;
11877 }
119- const payload = decrypted . subarray ( timestampLength + nonceLength ) ;
12078
79+ const payload = decrypted . subarray ( timestampLength + nonceLength ) ;
12180 const responseString = String . fromCharCode . apply ( String , new Uint8Array ( payload ) ) ;
12281 return JSON . parse ( responseString ) ;
12382}
12483
125- /**
126- * Creates an encrypted "envelope" to send to the UID2 API
127- * The envelope contains: timestamp, nonce, and the payload (user email)
128- * This format is required by the UID2 API for all token generation requests.
129- * @param {string } payload - The JSON string to encrypt (e.g., '{"email": "user@example .com"}')
130- * @returns {Object } Object containing the encrypted envelope and nonce
131- */
84+ // Creates encrypted envelope for UID2 API request
13285function createEnvelope ( payload ) {
13386 const millisec = BigInt ( Date . now ( ) ) ;
13487 const bufferMillisec = new ArrayBuffer ( timestampLength ) ;
@@ -140,28 +93,16 @@ function createEnvelope(payload) {
14093
14194 const { ciphertext, iv } = encryptRequest ( body , uid2ClientSecret ) ;
14295
143- const envelopeVersion = Buffer . alloc ( 1 , 1 ) ;
144- const envelope = bufferToBase64 ( Buffer . concat ( [ envelopeVersion , iv , Buffer . from ( new Uint8Array ( ciphertext ) ) ] ) ) ;
145- return { envelope : envelope , nonce : nonce } ;
96+ const envelopeVersion = Buffer . alloc ( 1 , 1 ) ;
97+ const envelope = bufferToBase64 ( Buffer . concat ( [ envelopeVersion , iv , Buffer . from ( new Uint8Array ( ciphertext ) ) ] ) ) ;
98+ return { envelope, nonce } ;
14699}
147100
148101// ============================================================================
149- // API ENDPOINT: Token Generation
102+ // API Endpoint
150103// ============================================================================
151104
152- /**
153- * POST /login
154- * Generates a UID2 token for the given email address
155- *
156- * This endpoint:
157- * 1. Receives an email from the front-end
158- * 2. Encrypts it and sends to UID2 API's /v2/token/generate endpoint
159- * 3. Decrypts the response
160- * 4. Returns the UID2 identity (token) as JSON to the front-end
161- *
162- * Request body: { email: "user@example .com" }
163- * Response: { identity: { advertising_token: "...", refresh_token: "...", ... } }
164- */
105+ // POST /login - Generates UID2 token for email address
165106app . post ( '/login' , async ( req , res ) => {
166107 const jsonEmail = JSON . stringify ( { email : req . body . email } ) ;
167108 const { envelope, nonce } = createEnvelope ( jsonEmail ) ;
@@ -179,14 +120,12 @@ app.post('/login', async (req, res) => {
179120 const response = decrypt ( encryptedResponse . data , uid2ClientSecret , nonce ) ;
180121
181122 if ( response . status === 'optout' ) {
182- // Opt-out is a valid state, return 200 with status
183123 res . json ( { status : 'optout' } ) ;
184124 } else if ( response . status !== 'success' ) {
185125 res . status ( 400 ) . json ( { error : 'Token generation failed' , status : response . status } ) ;
186126 } else if ( typeof response . body !== 'object' ) {
187127 res . status ( 400 ) . json ( { error : 'Unexpected response format' } ) ;
188128 } else {
189- // Return the identity (UID2 token) as JSON
190129 res . json ( { identity : response . body } ) ;
191130 }
192131 } catch ( error ) {
@@ -196,9 +135,9 @@ app.post('/login', async (req, res) => {
196135} ) ;
197136
198137// ============================================================================
199- // START THE SERVER
138+ // Start Server
200139// ============================================================================
140+
201141app . listen ( port , ( ) => {
202- console . log ( `UID2 Prebid Client-Server example listening at http://localhost:${ port } ` ) ;
142+ console . log ( `UID2 Prebid Client-Server example listening at http://localhost:${ port } ` ) ;
203143} ) ;
204-
0 commit comments