Skip to content

Add identity providers for ID5, LiveIntent, LiveRamp, ConnectID and UID2 - #1488

Draft
dhruv8sh wants to merge 25 commits into
feat/s2s-eid-collection-corefrom
feat/s2s-eid-vendors
Draft

dhruv8sh wants to merge 25 commits into
feat/s2s-eid-collection-corefrom
feat/s2s-eid-vendors

Conversation

@dhruv8sh

@dhruv8sh dhruv8sh commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #1487.

Summary

Per vendor

Provider Source Lockr capability
ID5 Lookup API plus the ID5 first-party cookie, including encoded cookies; carries linkType and keeps ext Yes
LiveIntent Lookup API that sends the LiveIntent first-party cookie; partner IDs are marked; needs a did- distributor ID No
LiveRamp First-party envelope cookie, including the bare envelope that Prebid stores in idl_env Yes
ConnectID Lookup API No
UID2 First-party token cookie Yes
SharedID Prebid _sharedid / _pubcid cookie as pubcid.org-style atype 1 EID; honours _pubcid_optout No
Criteo cto_bidid cookie, stored verbatim as the atype 1 EID Prebid sends No
Unified ID TDID from the pbjs-unifiedid cookie, with rtiPartner ext and adserver.org inserter/matcher, mm 4 No

Not supported, on purpose

  • Logged-in and hashed-email inputs. None of the providers use them.
  • UID2 token refresh.
  • LiveRamp server-side envelope refresh.
  • Capturing Lockr responses.

The plans list the remaining unported reference behaviours.

Changes

Area Change
crates/trusted-server-identity-providers/src/{id5,liveintent,liveramp,connectid,uid2,sharedid,criteo,unifiedid}.rs Provider implementations and tests
crates/trusted-server-identity-providers/src/common.rs Shared helpers: cookie name lists, Lockr cookie capability, parsing
crates/trusted-server-core/src/ec/provider.rs, ec/coordinator/ Framework hooks for own-cookie reading, provider ID, EID ext, and cookies in lookups
crates/trusted-server-core/src/settings.rs, adapter-fastly/src/app.rs Passes the provider ID and registers providers
trusted-server.example.toml Example provider config, using example.com hosts
docs/superpowers/plans/2026-11-02-identity-provider-*.md One plan per provider plus the Lockr capability

Closes

Part of #1246 and #1245. No issue is closed yet.

Spec

The spec is in #1487. This PR adds only plans, no new spec.

Test plan

  • cargo test-fastly && cargo test-fastly-reuse && cargo test-axum && cargo test-cloudflare && cargo test-spin
  • All 8 clippy aliases
  • cargo fmt --all -- --check
  • Parity tests, plus the template_build_digest test and its clippy run
  • scripts/lint-wasm-clock.sh
  • JS vitest, format and lint
  • Docs and markdown prettier
  • ./scripts/test-cli.sh, the node pin guard, and ts dev lint domains --changed-vs origin/feat/s2s-eid-collection-core
  • shellcheck (not installed locally; this PR doesn't touch those scripts)
  • Manual testing via fastly compute serve

Checklist

  • Changes follow AGENTS.md conventions
  • No unwrap() in production code
  • Uses log macros
  • New code has tests
  • No secrets or credentials committed

@dhruv8sh dhruv8sh self-assigned this Nov 2, 2026
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Add an optional IdentityProvider::read_request_cookies step that runs for providers with due sources before any lookup. Cookie IDs pass the same consent gates, validation and write plan as lookup results and replace the lookup. The provider endpoint becomes optional so cookie-only kinds need none; lookup kinds reject a missing endpoint.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Partner attributes such as bidswitch or magnite now carry the UID ext {provider: liveintent.com} that Prebid's LiveIntent module sets, while nonId stays bare. LiveIntent answers 400 Malformed did to any distributor ID that is not a did- ID, so the build rejects one.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Send _lc2_fpi as duid, resolve attributes from LiveIntent's fixed attribute table, keep reply segments as the nonId EID ext and mark the Trade Desk ID with matcher and rtiPartner, as the reference provider and Prebid do.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Prebid's identityLink ID module stores the envelope it fetches bare under its storage name, commonly idl_env, rather than the base64 JSON that ATS writes to _lr_env. Read idl_env after _lr_env by default and accept a base64-alphabet value that does not decode to JSON as a bare envelope.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Reads the publisher common ID from _sharedid, falling back to _pubcid, as a device-based pubcid.org EID, and honours the _pubcid_optout cookie.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Stores Criteo's bid ID verbatim as the device-based EID Prebid sends, with no server call.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Stores The Trade Desk ID with the rtiPartner ext, inserter, matcher and mm that Prebid sets.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Providers now report found IDs, an opt-out or nothing from their first-party cookies. An opt-out skips the provider's lookup as skipped_opted_out and removes its stored sources in the write plan, without a browser fallback. ID5 (universal_uid 0), UID2 (Prebid latestToken optout) and SharedID (_pubcid_optout) report opt-outs.

Cookies are read on every consented navigation, so an opt-out or changed ID is noticed while sources hold live UIDs; a cookie repeating the held UIDs is not rewritten, and lookups still respect due status.

UID2 parses Prebid's stored-tokens JSON and stores only latestToken.advertising_token, never JSON verbatim. Provider-stated absolute expiry is clamped to 30 days after the request in validation. Adds LiveRamp envelope length tests around the 1024-byte UID limit.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
@jwrosewell

Copy link
Copy Markdown
Collaborator

@dhruv8sh, the same point as on #1487. Directionally, eight identity vendors as files in one shared crate is not compatible with V2 (the 55 pull requests tracked in #777, merged in order), where each vendor is a module in a folder of its own at identity/<vendor> with its own named maintainer, so each provider owns and maintains its module.

The V2 spec is identifier-modules, with the folder layout in integrations-crate, both in #1342. The associated pull request is #1382 (a module hands core its identifiers, starting with the Prebid EID cookie).

Could you evaluate the V2 spec and #1382 before progressing this pull request?

…s server side

UID2 refreshes its stored advertising token with the stored refresh token and decrypts the AES-256-GCM reply; an optout reply removes the token. SharedID generates a random UUID v4 into KV only, kept for 30 days, when no cookie or stored ID exists. LiveRamp, when given an endpoint, placement ID and Custom ID namespace, looks up a RampID envelope by Custom ID built from the stable EC ID; a 204 reply is an opt-out.

Port the after-response collection, refresh-state, opt-out and rate_limit_per_hour framework changes, and update the vendor plans and operator docs.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
ts config validate, push and diff now build every enabled identity provider of a registered kind in both collection phases, so a provider-specific setting error (such as a liveramp endpoint without custom_id_namespace) fails the command before deploy. At runtime the same error disables every provider for each request.

Partner tokens are replaced with placeholders for the check, as core deploy validation already does.

Signed-off-by: dhruv8sh <dhruv8sh@proton.me>

This branch has not been deployed

No deployments
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