Repository navigation
Conversation
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>
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>
…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>
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>
…o large Match Prebid's agent type for the resolved Trade Desk ID, and leave out a segments ext over MAX_EXT_BYTES instead of losing the whole nonId EID. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Treat a missing or zero ttl as 14 days, read a missing lastSynced as fresh, and accept the lowercase connectid key. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Correct the UID2, LiveRamp, ID5, ConnectID, LiveIntent and Criteo plans. Describe placeholder IDs as no ID rather than an opt-out, name the client settings that put tokens in cookies, and mark allowed_domains as required only with an endpoint. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Carry the request cookies through the after-response lookup path, require a consented row in the coordinator tests, and update the provider tests for the owner-scoped OwnedEntries view and the partner-aware after-response builder. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
The coordinator now reports only a 404 as no match before parsing. A 204 reaches the provider, so LiveRamp's 204 opt-out clears its sources and is remembered, while ID5 and UID2 map their own 204 to no match. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
LookupInput carries the coordinator's request time and RequestCookies carries it to cookie readers, so the UID2 and ConnectID expiry checks and ID5's ts field use the navigation's one clock reading. Provider tests now read cookies at a fixed time. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Validation dropped refresh credentials whose refresh time had passed, so a live UID2 identity imported after its refresh_from, or kept through a failed refresh, could never be refreshed again. Due state is now stored and the source stays due; rate_limit_per_hour bounds the retries. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
A server-side refresh updates the row but not the browser's cookies, so the next navigation's older __uid_2 token replaced the refreshed token and its refresh state. Providers can now ask the coordinator to keep a live stored UID whose absolute expiry outlives the cookie's; UID2 does. A cookie opt-out still wins, and a newer SDK token is still taken. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Cookie and consent-derived opt-outs no longer get the 30-day lockout: lookups now say whether they remember, keep or forget the provider's opt-out, and only an opt-out a vendor server reports is remembered. The vendor's cookies are read before a remembered opt-out is checked, so an ID in them forgets the opt-out and is stored. ID5's "0" stays an opt-out. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Validation already clamped absolute expiries; ProviderExpiry::After is now clamped to the same 30 days, so the bound no longer depends on each provider. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Generation reuses the generated UID the row still holds after it expires, so the ID stays stable for as long as the row lives rather than changing every 30 days. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
The unchanged-cookie and failed-refresh regressions now run dispatch, collect and plan_write for a 404, timeout, 502, invalid reply and rate limit, each with a no-cookie control, and assert that no write is planned. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…ient The fetch body now carries provider (provider_name, defaulting to the publisher domain), domain and origin like ID5's Prebid Server module, instead of o, v, tml and nbPage. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Prebid's Lockr AIM module does not run where GDPR applies, so a Lockr cookie on such a request is a leftover; cookie readers now ignore Lockr cookies there. The example tables use Lockr keys that differ from the vendors' own cookies, and the docs say the default Lockr keys are already read as own cookies. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…pping file Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
LiveIntent now applies the shared usable-ID check, so a blank or 0 ID reads as no match. A LiveRamp envelope entry without a type no longer fails the whole reply. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Prebid's LiveIntent module sets the resolved Trade Desk ID's ext.provider to the page domain, falling back to liveintent.com, and copies the reply's m next to segments in the nonId EID ext. Carry the publisher domain to parse_response through the request context and build both ext values the same way. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
The coordinator drops sources a provider excludes where GDPR applies only when it writes the row, so a UID2 UID stored outside GDPR still reached bidders until the next committed write. Mark those sources in the partner registry for every configured provider and skip them in live_eids for a GDPR visitor. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Prebid's ID5 module sends the cached reply's signature as s so ID5 can return the same ID. Keep a non-empty reply signature as the UIDs' private refresh state, due a tenth of the TTL before they expire, and send it as s in the next fetch. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
Read the cookie named by the Prebid sharedId module's storage.name, default the source to pubcid.org with atype 1, and keep a stored SharedID for as long as the row lives instead of letting a different cookie replace it after a day. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
…provider Core cannot see the provider crate's kinds, so its deploy validation refused any enabled identity provider. ts config already builds every enabled provider, which refuses an unregistered kind; core now leaves that check to it. Signed-off-by: dhruv8sh <dhruv8sh@proton.me>
dhruv8sh
force-pushed
the
feat/s2s-eid-vendors
branch
from
November 12, 2026 14:11
aa66842 to
4fd9bd8
Compare
dhruv8sh
marked this pull request as draft
November 12, 2026 14:15
11 of 15 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sharedIdmodule config, defaults its source topubcid.org(atype 1), and keeps a stored SharedID for as long as the row exists.ts configalready runs. Core can't see the provider crate's kinds, so it refused every enabled provider at deploy.Changes
crates/trusted-server-core/src/ec/provider.rsIdentityProvider::keeps_stored_uidshook, defaulting tofalse. When it returnstrue, a live stored UID wins over a different cookie value.crates/trusted-server-core/src/ec/coordinator/mod.rscrates/trusted-server-core/src/settings.rssharedidprovider with nosourcesclaimspubcid.org. This usesserde(remote = "Self")so the default is applied once, at deserialization.crates/trusted-server-identity-providers/src/sharedid.rskeeps_stored_uids. Updates the docs and tests.crates/trusted-server-identity-providers/src/lib.rscookie_namesfromintegrations.prebid.managed_user_ids[].storage.namefor thesharedId/pubCommonIdmodule when its storage type is a cookie and the provider doesn't set its own names. Adds a test thatvalidate_providersrefuses an unregistered kind.crates/trusted-server-core/src/config.rsreject_providers_without_a_kind.ts configbuilds each enabled provider and refuses unregistered kinds.trusted-server.example.tomlBehaviour
storage = { type = "cookie", name = "_pubcid" }on the PrebidsharedIdmodule, only_pubcidis read. A cookie namedsharedIdis not._pubcid_optoutcookie still wins. Reading and storing still need EC consent plus EID consent (TCF Purposes 1 and 4), which the coordinator already enforces before reading cookies.Not in this PR
ts configchecks provider kinds but not the target adapter. Pushing an enabled provider to Axum, Cloudflare or Spin still fails at startup, as before.Closes
Follow-up into #1488 (base branch
feat/s2s-eid-vendors). No linked issue.Spec
Spec: implements review follow-ups to #1488, whose spec lives in that stack.
Test plan
cargo test-fastly && cargo test-axum(alsocargo test-cloudflare,cargo test-spin)cargo clippy-fastly && cargo clippy-axum(alsoclippy-cloudflare,clippy-cloudflare-wasm,clippy-spin-native,clippy-spin-wasm,clippy-cli,clippy-codegen)cargo fmt --all -- --checkcd crates/trusted-server-js/lib && npx vitest run(1838 passed, 1 skipped, on the pinned Node 24.20.0)cd crates/trusted-server-js/lib && npm run formatcd docs && npm run formatcargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1fastly compute serve./scripts/test-cli.sh;cargo test -p trusted-server-identity-providers(110 passed)Checklist
unwrap()in production code — useexpect("should ...")logmacros (notprintln!)