Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
3cefb97
Add the ID5 identity provider
dhruv8sh Nov 1, 2026
3ebb07b
Add the LiveIntent identity provider
dhruv8sh Nov 1, 2026
a66d1a2
Fix vendor expiry, opt-out and parsing issues
dhruv8sh Nov 2, 2026
5d82249
Let identity providers read their own first-party cookies
dhruv8sh Nov 2, 2026
9f043c4
Add the LiveRamp identity provider
dhruv8sh Nov 2, 2026
1982071
Add the Yahoo ConnectID identity provider
dhruv8sh Nov 2, 2026
bc5c0c3
Add the UID2 identity provider
dhruv8sh Nov 2, 2026
fb92551
Read the ID5 ID from its first-party cookie
dhruv8sh Nov 2, 2026
1434ced
Pass the configured provider ID to identity provider builds
dhruv8sh Nov 2, 2026
1b0c3c1
Use cookie name lists across cookie-reading providers
dhruv8sh Nov 2, 2026
101909f
Add a Lockr cookie capability for identity providers
dhruv8sh Nov 2, 2026
1cb9da8
Mark LiveIntent partner IDs and require a did- distributor ID
dhruv8sh Nov 2, 2026
94a1ef1
Let identity providers build an EID ext and read cookies in lookups
dhruv8sh Nov 2, 2026
4a24b30
Send the LiveIntent first-party cookie and port its reply mapping
dhruv8sh Nov 2, 2026
237e78d
Carry the ID5 linkType and keep ext from encoded ID5 cookies
dhruv8sh Nov 2, 2026
f379447
Note the reference provider behaviours left unported
dhruv8sh Nov 2, 2026
e4cbea7
Read the bare LiveRamp envelope Prebid stores in idl_env
dhruv8sh Nov 2, 2026
f549b40
Add a SharedID identity provider reading the Prebid first-party cookie
dhruv8sh Nov 2, 2026
3baa58b
Add a Criteo identity provider reading the cto_bidid cookie
dhruv8sh Nov 2, 2026
3b26dd5
Add a Unified ID identity provider reading the pbjs-unifiedid cookie
dhruv8sh Nov 2, 2026
eabbf95
Document that LiveIntent partner IDs need the publisher distributor ID
dhruv8sh Nov 2, 2026
0b1559e
Honour vendor cookie opt-outs and bound cookie-supplied expiry
dhruv8sh Nov 3, 2026
f547ae2
Refresh UID2 tokens, generate SharedIDs and look up LiveRamp envelope…
dhruv8sh Nov 4, 2026
7c13c8f
Build identity providers when validating the app config
dhruv8sh Nov 4, 2026
29506ee
Send ID5 GPP section IDs as an array and use the gs/v2 fetch path
dhruv8sh Nov 5, 2026
b5b7852
Send the RFC 3339 timestamp the ID5 gs/v2 fetch requires
dhruv8sh Nov 5, 2026
a932693
Log the HTTP status of a failed identity lookup
dhruv8sh Nov 5, 2026
34fcb5a
Treat an ID5 fetch reply with an opt-out UID as an opt-out
dhruv8sh Nov 5, 2026
267ae68
Omit empty LiveIntent segments from the nonId EID
dhruv8sh Nov 5, 2026
396a284
Read the first non-empty value among duplicate vendor cookies
dhruv8sh Nov 5, 2026
77f61ef
Check the lookup rate limit only once a request is built
dhruv8sh Nov 5, 2026
a7ebe40
Look up the due sources a vendor cookie did not fill
dhruv8sh Nov 5, 2026
96a72e6
Skip UID2 where GDPR applies
dhruv8sh Nov 5, 2026
ae375fe
Show the TCF vendor ID for the Criteo and Unified ID examples
dhruv8sh Nov 5, 2026
133bd3a
Note that the ConnectID opt-out is not visible server side
dhruv8sh Nov 5, 2026
ea2ed30
Drop UID2 IDs, including those LiveIntent resolves, where the visitor…
dhruv8sh Nov 5, 2026
2f90ca6
Generate a SharedID only when the publisher opts in
dhruv8sh Nov 6, 2026
3551605
Check every duplicate cookie for opt-outs and skip expired cookie IDs
dhruv8sh Nov 6, 2026
e273dad
Refresh a due UID even while its cookie repeats it
dhruv8sh Nov 6, 2026
9114d2e
Keep held cookie UIDs and refresh state while another source is due
dhruv8sh Nov 11, 2026
a051341
Hide cookie values from the RequestCookies Debug output
dhruv8sh Nov 11, 2026
cf1caad
Store the percent-decoded Criteo bid ID that Prebid sends
dhruv8sh Nov 11, 2026
339d28e
Parse LiveRamp v2 envelope replies and send server-to-server atype
dhruv8sh Nov 11, 2026
6e35816
Send ID5 gpp_sid comma-joined and IPv6 addresses as ipv6
dhruv8sh Nov 11, 2026
35ecd3f
Honour the UID2 SDK opt-out identity cookie
dhruv8sh Nov 11, 2026
a929ca9
Send LiveIntent's TDID as atype 1 and keep nonId when segments are to…
dhruv8sh Nov 11, 2026
a09bd10
Match Prebid's ConnectID cookie validity rules
dhruv8sh Nov 11, 2026
bac2f23
Align provider docs, plans and example config with the code
dhruv8sh Nov 11, 2026
739b062
Reconcile the vendor providers with the updated collection core
dhruv8sh Nov 12, 2026
39a25f4
Hand 204 lookup replies to the provider
dhruv8sh Nov 12, 2026
b8aead5
Pass the request time to identity providers
dhruv8sh Nov 12, 2026
834af25
Keep refresh state that is already due
dhruv8sh Nov 12, 2026
0a4f4c9
Keep a refreshed UID2 token over an older cookie token
dhruv8sh Nov 12, 2026
fb68944
Remember only vendor server opt-outs and let a cookie ID clear one
dhruv8sh Nov 12, 2026
3709669
Bound provider relative expiry to 30 days in validation
dhruv8sh Nov 12, 2026
5479280
Renew an expired generated SharedID instead of replacing it
dhruv8sh Nov 12, 2026
611459f
Test that the Fastly adapter joins every Cookie header for providers
dhruv8sh Nov 12, 2026
4fef057
Check the held-cookie regressions through the write plan
dhruv8sh Nov 12, 2026
707c6f4
Send ID5 the provider, domain and origin fields of its server-side cl…
dhruv8sh Nov 12, 2026
9d8cd2d
Skip Lockr cookies where GDPR applies and document the Lockr key overlap
dhruv8sh Nov 12, 2026
5d22274
Document the UID2 token-chain mitigations and LiveRamp's Custom ID ma…
dhruv8sh Nov 12, 2026
371e0cc
Drop placeholder LiveIntent IDs and skip untyped LiveRamp envelopes
dhruv8sh Nov 12, 2026
edb64fd
Log review rounds 7 and 8 for the vendor identity providers
dhruv8sh Nov 12, 2026
a27323c
Name the commit that bounds UID2 refresh retries in the review log
dhruv8sh Nov 12, 2026
9889b96
Name the publisher domain as the LiveIntent TDID provider and keep m
dhruv8sh Nov 12, 2026
ec24bf5
Withhold stored UIDs of GDPR-excluded sources from egress
dhruv8sh Nov 12, 2026
a0e4190
Send the previous ID5 signature back as s
dhruv8sh Nov 12, 2026
fef8d31
Handle SharedID the way Prebid defines it
dhruv8sh Nov 12, 2026
569c1c3
Check registered provider kinds at deploy instead of rejecting every …
dhruv8sh Nov 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 78 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ publish = false
version = "0.1.0"

[workspace.dependencies]
aes-gcm = { version = "0.11", default-features = false, features = ["aes", "alloc"] }
anyhow = "1"
assert_cmd = "2"
async-stream = "0.3"
Expand Down
44 changes: 42 additions & 2 deletions crates/trusted-server-adapter-fastly/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ use trusted_server_core::ec::eid_types::UnixSeconds;
use trusted_server_core::ec::identify::{cors_preflight_identify, handle_identify};
use trusted_server_core::ec::kv::KvIdentityGraph;
use trusted_server_core::ec::page_load::NavigationPermit;
use trusted_server_core::ec::provider::ClientSignals;
use trusted_server_core::ec::provider::{ClientSignals, RequestCookies};
use trusted_server_core::ec::registry::PartnerRegistry;
use trusted_server_core::ec::{EcContext, EcKvSnapshot, EidSyncSource};
use trusted_server_core::error::{IntoHttpResponse as _, TrustedServerError};
Expand Down Expand Up @@ -395,6 +395,7 @@ pub(crate) struct AfterResponseLookups {
pub(crate) ec_id: String,
pub(crate) client_ip: Option<IpAddr>,
pub(crate) user_agent: Option<String>,
pub(crate) cookie_header: String,
}

/// Identity work a navigation hands to the entry point.
Expand Down Expand Up @@ -427,6 +428,7 @@ pub(crate) fn take_navigation_lookups() -> NavigationLookups {
struct ProviderRequestSignals<'a> {
client_ip: Option<IpAddr>,
user_agent: Option<&'a str>,
cookie_header: String,
}

impl<'a> ProviderRequestSignals<'a> {
Expand All @@ -439,10 +441,23 @@ impl<'a> ProviderRequestSignals<'a> {
.headers()
.get(header::USER_AGENT)
.and_then(|value| value.to_str().ok()),
cookie_header: joined_cookie_header(req),
}
}
}

/// Joins every `Cookie` header on the request into one `; `-separated value.
///
/// HTTP/2 and HTTP/3 clients may split cookies across several headers.
fn joined_cookie_header(req: &Request) -> String {
req.headers()
.get_all(header::COOKIE)
.iter()
.filter_map(|value| value.to_str().ok())
.collect::<Vec<_>>()
.join("; ")
}

/// Captures the request signals for after-response identity lookups on a
/// permitted publisher navigation.
///
Expand All @@ -461,6 +476,7 @@ fn prepare_after_response_lookups(
ec_id,
client_ip: signals.client_ip,
user_agent: signals.user_agent.map(str::to_owned),
cookie_header: signals.cookie_header,
})
}

Expand Down Expand Up @@ -502,6 +518,7 @@ async fn dispatch_identity_lookups(
user_agent: signals.user_agent,
},
publisher_domain: &state.settings.publisher.domain,
cookies: RequestCookies::new(&signals.cookie_header),
rate_limiter: &limiter,
now: UnixSeconds::new(now),
},
Expand Down Expand Up @@ -1630,7 +1647,7 @@ mod tests {
use trusted_server_core::ec::provider::{
EidLevelFields, EidShape, IdentityProvider, LookupInput, LookupOutcome,
ProviderCapabilities, ProviderEid, ProviderError, ProviderExpiry, ProviderRequest,
ProviderResponse, ProviderUid, SourceCapability, SourceInput,
ProviderResponse, ProviderUid, RequestCookies, SourceCapability, SourceInput,
};
use trusted_server_core::ec::registry::PartnerRegistry;
use trusted_server_core::error::TrustedServerError;
Expand Down Expand Up @@ -2799,6 +2816,29 @@ mod tests {
request
}

#[test]
fn provider_cookies_join_every_cookie_header() {
// Arrange: HTTP/2 clients may split cookies across headers.
let mut request = navigation_request("/article");
let headers = request.headers_mut();
headers.append(header::COOKIE, HeaderValue::from_static("a=1; b=2"));
headers.append(header::COOKIE, HeaderValue::from_static("vendor_id=c-1"));

// Act
let joined = super::joined_cookie_header(&request);

// Assert
assert_eq!(
joined, "a=1; b=2; vendor_id=c-1",
"should join every Cookie header"
);
assert_eq!(
RequestCookies::new(&joined).get("vendor_id"),
Some("c-1"),
"should let providers read a cookie from a later header"
);
}

fn take_finalize_state(response: &mut Response) -> super::EcFinalizeState {
response
.extensions_mut()
Expand Down
3 changes: 2 additions & 1 deletion crates/trusted-server-adapter-fastly/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use trusted_server_core::ec::eid_types::UnixSeconds;
use trusted_server_core::ec::finalize::ec_finalize_response;
use trusted_server_core::ec::kv::KvIdentityGraph;
use trusted_server_core::ec::page_load::NavigationPermit;
use trusted_server_core::ec::provider::ClientSignals;
use trusted_server_core::ec::provider::{ClientSignals, RequestCookies};
use trusted_server_core::ec::pull_sync::{
PullSyncContext, build_pull_sync_context, dispatch_pull_sync,
};
Expand Down Expand Up @@ -801,6 +801,7 @@ pub(crate) fn run_after_response_lookups(
user_agent: lookups.user_agent.as_deref(),
},
publisher_domain: &settings.publisher.domain,
cookies: RequestCookies::new(&lookups.cookie_header),
rate_limiter: &limiter,
now: UnixSeconds::new(now),
},
Expand Down
2 changes: 2 additions & 0 deletions crates/trusted-server-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ toml = { workspace = true }
toml_edit = { workspace = true }
tracing = { workspace = true }
trusted-server-core = { workspace = true }
trusted-server-identity-providers = { workspace = true }
url = { workspace = true }
uuid = { workspace = true }
validator = { workspace = true }
which = { workspace = true }

# `ts dev lint domains` and `ts dev install-hooks` drive all git access through
Expand Down
Loading