Skip to content

Commit

Permalink
lockr AIM user module: initial release (#11159)
Browse files Browse the repository at this point in the history
* Adding Lockr AIM module and tests

* formatting

* Fix formatting

* format

* fix formatting

* add paapi back

* added markdown file

* 20240324 Fixed Storage Manager | lockrAIMIdSystem.js

* Updated to use Prebid Storage Manager | lockrAIMIdSystem_shared.js

* added the fix for the comments

* removed the unnecessary console

---------

Co-authored-by: chris-lockr <chris@loc.kr>
Co-authored-by: avin-lockr <avin@loc.kr>
  • Loading branch information
3 people authored May 1, 2024
1 parent 51c63b6 commit 0e58601
Show file tree
Hide file tree
Showing 4 changed files with 409 additions and 6 deletions.
13 changes: 7 additions & 6 deletions modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"33acrossIdSystem",
"admixerIdSystem",
"adtelligentIdSystem",
"adqueryIdSystem",
"amxIdSystem",
"britepoolIdSystem",
"connectIdSystem",
Expand All @@ -13,23 +14,28 @@
"deepintentDpesIdSystem",
"dmdIdSystem",
"fabrickIdSystem",
"freepassIdSystem",
"hadronIdSystem",
"id5IdSystem",
"ftrackIdSystem",
"gravitoIdSystem",
"identityLinkIdSystem",
"idxIdSystem",
"imuIdSystem",
"intentIqIdSystem",
"justIdSystem",
"kinessoIdSystem",
"liveIntentIdSystem",
"lockrAIMIdSystem",
"lotamePanoramaIdSystem",
"merkleIdSystem",
"mwOpenLinkIdSystem",
"mygaruIdSystem",
"naveggIdSystem",
"netIdSystem",
"novatiqIdSystem",
"oneKeyIdSystem",
"operaadsIdSystem",
"parrableIdSystem",
"pubProvidedIdSystem",
"publinkIdSystem",
Expand All @@ -44,12 +50,7 @@
"euidIdSystem",
"unifiedIdSystem",
"verizonMediaIdSystem",
"zeotapIdPlusIdSystem",
"adqueryIdSystem",
"gravitoIdSystem",
"freepassIdSystem",
"operaadsIdSystem",
"mygaruIdSystem"
"zeotapIdPlusIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
165 changes: 165 additions & 0 deletions modules/lockrAIMIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/**
* This module adds lockr AIM ID support to the User ID module
* The {@link module:modules/userId} module is required.
* @module modules/lockrAIMIdSystem
* @requires module:modules/userId
*/

import { submodule } from '../src/hook.js';
import { ajax } from '../src/ajax.js';
import { logInfo, logWarn } from '../src/utils.js';
import { getStorageManager } from '../src/storageManager.js';
import { MODULE_TYPE_UID } from '../src/activities/modules.js';
import { gppDataHandler } from '../src/adapterManager.js';

/**
* @typedef {import('../modules/userId/index.js').Submodule} Submodule
* @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
* @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
* @typedef {import('../modules/userId/index.js').lockrAIMId} lockrAIMId
*/

const MODULE_NAME = 'lockrAIMId'
const LOG_PRE_FIX = 'lockr-AIM: ';

const AIM_PROD_URL = 'https://identity.loc.kr';

export const lockrAIMCodeVersion = '1.0';

export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME })

function createLogger(logger, prefix) {
return function (...strings) {
logger(prefix + ' ', ...strings);
}
}

const _logInfo = createLogger(logInfo, LOG_PRE_FIX);
const _logWarn = createLogger(logWarn, LOG_PRE_FIX);

/** @type {Submodule} */
export const lockrAIMSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: MODULE_NAME,

init() {
_logInfo('lockrAIM Initialization complete');
},

/**
* performs action to obtain id and return a value.
* @function
* @param {SubmoduleConfig} [config]
* @param {ConsentData|undefined} consentData
* @returns {lockrAIMId}
*/
getId(config, consentData) {
if (consentData?.gdprApplies === true) {
_logWarn('lockrAIM is not intended for use where GDPR applies. The lockrAIM module will not run');
return undefined;
}

const gppConsent = gppDataHandler.getConsentData();
let gppString = '';
if (gppConsent) {
gppString = gppConsent.gppString;
}
const mappedConfig = {
appID: config?.params?.appID,
email: config?.params?.email,
baseUrl: AIM_PROD_URL,
};

_logInfo('lockr AIM configurations loaded and mapped.', mappedConfig);
if (!mappedConfig.appID || !mappedConfig.email) {
return undefined;
}
const tokenGenerator = new LockrAIMApiClient(mappedConfig, _logInfo, _logWarn, storage, gppString);
const result = tokenGenerator.generateToken();
_logInfo('lockr AIM results generated');
return result;
}
}

class LockrAIMApiClient {
static expiryDateKeys = [];
static canRefreshToken = false;

constructor(opts, logInfo, logWarn, prebidStorageManager, gppString) {
this._baseUrl = opts.baseUrl;
this._appID = opts.appID;
this._email = opts.email;
this._logInfo = logInfo;
this._logWarn = logWarn;
this._gppString = gppString;
this.prebidStorageManager = prebidStorageManager;
LockrAIMApiClient.expiryDateKeys = this.prebidStorageManager.getDataFromLocalStorage('lockr_expiry_keys') ? JSON.parse(this.prebidStorageManager.getDataFromLocalStorage('lockr_expiry_keys')) : []
this.initializeRefresher();
}

async generateToken(type = 'email', value) {
const url = this._baseUrl + '/publisher/app/v1/identityLockr/generate-tokens';
let rejectPromise;
const promise = new Promise((resolve, reject) => {
rejectPromise = reject;
});
const requestBody = {
appID: this._appID,
data: {
type: type,
value: value ?? this._email,
gppString: this._gppString,
}
}
this._logInfo('Sending the token generation request')
ajax(url, {
success: (responseText) => {
try {
const response = JSON.parse(responseText);
LockrAIMApiClient.canRefreshToken = false;
const token = response.lockrMappingToken;
this.prebidStorageManager.setDataInLocalStorage('ilui', token);
response.data.forEach(cookieitem => {
const settings = cookieitem?.settings;
this.prebidStorageManager.setDataInLocalStorage(`${cookieitem.key_name}_expiry`, cookieitem.identity_expires);
if (!LockrAIMApiClient.expiryDateKeys.includes(`${cookieitem.key_name}_expiry`)) {
LockrAIMApiClient.expiryDateKeys.push(`${cookieitem.key_name}_expiry`);
}
this.prebidStorageManager.setDataInLocalStorage('lockr_expiry_keys', JSON.stringify(LockrAIMApiClient.expiryDateKeys));
if (!settings?.dropLocalStorage) {
this.prebidStorageManager.setDataInLocalStorage(cookieitem.key_name, cookieitem.advertising_token);
}
if (!settings?.dropCookie) {
this.prebidStorageManager.setCookie(cookieitem.key_name, cookieitem.advertising_token);
}
});
LockrAIMApiClient.canRefreshToken = true;
return;
} catch (_err) {
this._logWarn(_err);
rejectPromise(responseText);
LockrAIMApiClient.canRefreshToken = true;
}
}
}, JSON.stringify(requestBody), { method: 'POST', contentType: 'application/json;charset=UTF-8' });
return promise;
}

async initializeRefresher() {
setInterval(() => {
LockrAIMApiClient.expiryDateKeys.forEach(expiryItem => {
const currentMillis = new Date().getTime();
const dateMillis = this.prebidStorageManager.getDataFromLocalStorage(expiryItem);
if (currentMillis > dateMillis && dateMillis !== null && this.prebidStorageManager.getDataFromLocalStorage('ilui') && LockrAIMApiClient.canRefreshToken) {
this.generateToken('refresh', this.prebidStorageManager.getDataFromLocalStorage('ilui'));
}
})
}, 1000);
}
}

// Register submodule for userId
submodule('userId', lockrAIMSubmodule);
165 changes: 165 additions & 0 deletions modules/lockrAIMIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
## **lockr AIM**

Alternative Identity Manager (AIM) is a unified container for identity and data management.
With AIM’s self-service platform, publishers seamlessly integrate and activate alternative IDs like LiveRamp’s Authenticated Traffic Solution (ATS), Unified ID 2.0 (UID2), ID5 and more. The burden of due diligence and maintenance, coupled with the benefits of server-side calls result in the adoption of multiple alternative IDs, clean rooms like InfoSum and CDPs like Blueconic based on their specific needs.

### **Account Creation | AIM**

Sign up for an [Identity lockr account.](https://sso.loc.kr/console/signup)
Setup your app and activate the AIM library.
Compile Prebid with the appropriate configurations, and deploy.

### **Configuration | AIM**

First, make sure to add the lockr’s AIM submodule to your Prebid.js package with:
The following configuration parameters are available:
AIM supports all Single Sign On functions, newsletter registrations, UTM parameters, etc. For the sake of clarity, a few examples are shared below.
**Google oAuth: **
If you are using Google oAuth (_as an example_), the onSignIn function will subsequently call window.lockr.setAdditionalData function and include a raw email.

```
function onSignIn(googleUser) {
pbjs.setConfig({
userSync: {
userIds: [{
name: 'lockrAIMId',
params: {
email: 'john@example.com',
appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc'
}
}]
}
});
}
```

**Facebook oAuth:**
If you are using Facebook Login (_as an example_), the statusChangeCallback function will subsequently call window.lockr.setAdditionalData function and include a raw email.

```
function statusChangeCallback(response) {
console.log('statusChangeCallback');
console.log(response);
if(response.status === 'connected'){
pbjs.setConfig({
userSync: {
userIds: [{
name: 'lockrAIMId',
params: {
email: 'john@example.com',
appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc'
}
}]
}
});
}else{
document.getElementById('status').innerHTML = 'Please login';
}
}
```

**Note:** The above code can be triggered from anywhere on the domain (i.e. a subscription form).

<table>
<tr>
<td><strong>Param</strong>
</td>
<td><strong>Scope</strong>
</td>
<td><strong>Type</strong>
</td>
<td><strong>Description</strong>
</td>
<td><strong>Example</strong>
</td>
</tr>
<tr>
<td>name
</td>
<td>Required
</td>
<td>String
</td>
<td>The name of this module: <code>"lockrAIMId"</code>
</td>
<td><code>"lockrAIMId"</code>
</td>
</tr>
<tr>
<td>params
</td>
<td>Required
</td>
<td>Object
</td>
<td>Details for the configuration.
</td>
<td>
</td>
</tr>
<tr>
<td>params.email
</td>
<td>Required
</td>
<td>String
</td>
<td>Email address for identity tokens.
</td>
<td><code>test@example.com</code>
</td>
</tr>
<tr>
<td>params.appID
</td>
<td>Required
</td>
<td>String
</td>
<td>Identity lockr appID
</td>
<td><code>test@example.com</code>
</td>
</tr>
</table>

**lockr AIM Example**

```
pbjs.setConfig({
userSync: {
userIds: [{
name: 'lockrAIMId',
params: {
email: 'test@example.com',
appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc'
}
}]
}
});
```

_Note_: lockr’s AIM self-service interface empowers publishers with the ability to pass the alternative IDs activated back to the client as local storage or as a first party cookie. Each Identity Provider can be individually set to restrict from client-side delivery and instead be retained as an authentication event within Identity lockr. In this case no data is lost, but instead maintained for automated or manual sharing to any Data Endpoint.

**Troubleshooting and Error handling:**

1. Navigate to the domain where Prebid.js Library is integrated.
2. Go to the 'Network' tab of your Developer Tools. Search for “prebid.js”
3. In the application tab, you can confirm any activated Identity Provider (if client-side storage is turned on in AIM’s Identity Provider settings).
4. Debugging:
Enable the debug flag to true in the setConfig call:

```
pbjs.setConfig({
debug: true,
userSync: {
userIds: [{
name: 'lockrAIMId',
params: {
email: 'test@example.com',
appID: 'e84afc5f-4adf-4144-949f-1de5bd151fcc'
}
}]
}
});
```
Loading

0 comments on commit 0e58601

Please sign in to comment.