Skip to content

uid2: add refreshUid2Token protocol client - #328

Open
mosherBT wants to merge 1 commit into
masterfrom
uid2-refresh-addon
Open

uid2: add refreshUid2Token protocol client#328
mosherBT wants to merge 1 commit into
masterfrom
uid2-refresh-addon

Conversation

@mosherBT

@mosherBT mosherBT commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Why

UID2 tokens expire and must be refreshed client-side against the UID2 operator. web-sdk has no refresh client; refreshUid2Token is duplicated in 18 solutions bundles.

What Changed

  • addons: new lib/addons/uid2-refresh.ts exporting refreshUid2Token(refreshToken, refreshResponseKey) — POSTs the refresh token to the UID2 operator, AES-GCM-decrypts the response (12-byte nonce prefix, refresh_response_key), returns the body or null on non-OK / opt-out / missing advertising_token. Malformed responses throw; error policy stays with the caller.
  • addons: Uid2RefData type — the response body and the _ref shape on cached EIDs.

How to Test

Unit tests cover a webcrypto round-trip, raw-body POST, non-OK, opt-out, missing token, and undecryptable payload.

  • Tested
  • Docs updated

Notes

  • First of three PRs for the addon: protocol client, then cache apply, then the refreshStaleUid2s orchestrator.

  • Breaking change

  • Requires release

@mosherBT
mosherBT requested review from a team as code owners August 24, 2026 19:50
@mosherBT mosherBT self-assigned this Aug 24, 2026
const cryptoKey = await crypto.subtle.importKey("raw", keyBytes, { name: "AES-GCM" }, false, ["decrypt"]);
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: nonce }, cryptoKey, ciphertext);
const parsed = JSON.parse(new TextDecoder().decode(decrypted));
return parsed.body?.advertising_token ? (parsed.body as Uid2RefData) : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we return null for either a opt-out, a non-ok response or a success with a missing the advertising_token. Maybe we should have clearer distinct results.

identity_expires: number;
};

const UID2_REFRESH_ENDPOINT = "https://prod.uidapi.com/v2/token/refresh";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to have this be an arg to refreshUid2Token instead of hardcoded

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or at least an arg with a default like endpoint = UID2_REFRESH_ENDPOINT

@etiennelatendresse-optable

Copy link
Copy Markdown
Contributor

Other addons had an update to the README.md. We probably want one here also

async function refreshUid2Token(refreshToken: string, refreshResponseKey: string): Promise<Uid2RefData | null> {
const response = await fetch(UID2_REFRESH_ENDPOINT, {
method: "POST",
headers: { "Content-Type": "application/json" },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type seems to be a raw refresh-token string so "Content-Type": "text/plain" would be more accurate.

const cryptoKey = await crypto.subtle.importKey("raw", keyBytes, { name: "AES-GCM" }, false, ["decrypt"]);
const decrypted = await crypto.subtle.decrypt({ name: "AES-GCM", iv: nonce }, cryptoKey, ciphertext);
const parsed = JSON.parse(new TextDecoder().decode(decrypted));
return parsed.body?.advertising_token ? (parsed.body as Uid2RefData) : null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we only validate on one field advertising_token before casting to Uid2RefData. We might want to do further check for things like missing refresh_expires or refresh_token.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants