Skip to content

Commit

Permalink
Explainer for cross-origin trusted signals (#1156)
Browse files Browse the repository at this point in the history
Spec in #1197
  • Loading branch information
morlovich authored Jul 11, 2024
1 parent d0fc360 commit 38d3b02
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 5 deletions.
90 changes: 86 additions & 4 deletions FLEDGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ See [the Protected Audience API specification](https://wicg.github.io/turtledove
- [2.5.2 Using Response Headers](#252-using-response-headers)
- [3. Buyers Provide Ads and Bidding Functions (BYOS for now)](#3-buyers-provide-ads-and-bidding-functions-byos-for-now)
- [3.1 Fetching Real-Time Data from a Trusted Server](#31-fetching-real-time-data-from-a-trusted-server)
- [3.1.1 Cross-Origin Trusted Server Signals](#311-cross-origin-trusted-server-signals)
- [3.2 On-Device Bidding](#32-on-device-bidding)
- [3.3 Metadata with the Ad Bid](#33-metadata-with-the-ad-bid)
- [3.4 Ads Composed of Multiple Pieces](#34-ads-composed-of-multiple-pieces)
Expand Down Expand Up @@ -505,7 +506,7 @@ Once the bids are known, the seller runs code inside an _auction worklet_. With

```
scoreAd(adMetadata, bid, auctionConfig, trustedScoringSignals, browserSignals,
directFromSellerSignals) {
directFromSellerSignals, crossOriginTrustedSignals) {
...
return {desirability: desirabilityScoreForThisAd,
incomingBidInSellerCurrency:
Expand All @@ -520,7 +521,7 @@ The function gets called once for each candidate ad in the auction. The argumen
* adMetadata: Arbitrary metadata provided by the buyer.
* bid: A numerical bid value.
* auctionConfig: The auction configuration object passed to `navigator.runAdAuction()`.
* trustedScoringSignals: A value retrieved from a real-time trusted server chosen by the seller and reflecting the seller's opinion of this particular creative, as further described in [3.1 Fetching Real-Time Data from a Trusted Server](#31-fetching-real-time-data-from-a-trusted-server) below. (In the case of [ads composed of multiple pieces](https://github.com/WICG/turtledove/blob/main/FLEDGE.md#34-ads-composed-of-multiple-pieces) this should instead be some collection of values, structure TBD.)
* trustedScoringSignals: A value retrieved from a real-time trusted server chosen by the seller and reflecting the seller's opinion of this particular creative, as further described in [3.1 Fetching Real-Time Data from a Trusted Server](#31-fetching-real-time-data-from-a-trusted-server) below. This is used when the server is same-origin to the seller; crossOriginTrustedSignals is used otherwise.
* browserSignals: An object constructed by the browser, containing information that the browser knows and which the seller's auction script might want to verify:
```
{ 'topWindowHostname': 'www.example-publisher.com',
Expand All @@ -538,6 +539,11 @@ The function gets called once for each candidate ad in the auction. The argumen
* directFromSellerSignals is an object that may contain the following fields:
* sellerSignals: Like auctionConfig.sellerSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?sellerSignals`.
* auctionSignals: Like auctionConfig.auctionSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?auctionSignals`.
* crossOriginTrustedSignals: like `trustedScoringSignals`, but used when the server is cross-origin
to the seller script. The value is an object that has as a key the trusted server's origin, e.g.
`"https://example.org"`, and as value an object in format `trustedScoringSignals` uses. See
[3.1.1 Cross-Origin Trusted Server Signals](#311-cross-origin-trusted-server-signals) for more
details.

The output of `scoreAd()` is an object with the following fields:
* desirability: Number indicating how desirable this ad is. Any value that is zero or negative indicates that the ad cannot win the auction. (This could be used, for example, to eliminate any interest-group-targeted ad that would not beat a contextually-targeted candidate.) The winner of the auction is the ad object which was given the highest score.
Expand Down Expand Up @@ -765,14 +771,84 @@ For detailed specification and explainers of the trusted key-value server, see a
- [FLEDGE Key/Value Server APIs Explainer](https://github.com/WICG/turtledove/blob/master/FLEDGE_Key_Value_Server_API.md)
- [FLEDGE Key/Value Server Trust Model Explainer](https://github.com/privacysandbox/fledge-docs/blob/main/key_value_service_trust_model.md)

##### 3.1.1 Cross-Origin Trusted Server Signals

If the key-value server is on a different origin than the corresponding script, additional steps are
needed to ensure that sensitive information is not inappropriately leaked to, or is manipulated by,
a third party.

In the case of bidder signals, the following changes occur:
1. The fetch is a cross-origin [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) fetch
with `Origin:` set to the buyer script's origin.
2. The value is passed to `crossOriginTrustedSignals` parameter, not the `trustedBiddingSignals`
parameter, and there is one more level of nesting denoting the server's origin, e.g:

```
{
'https://www.kv-server.example': {
'keys': {
'key1': arbitrary_json,
'key2': arbitrary_json,
...},
'perInterestGroupData': {
'name1': {
'priorityVector': {
'signal1': number,
'signal2': number,
...}
},
...
}
}
}
```
3. The data version is passed in `browserSignals.crossOriginDataVersion`, not
`browserSignals.dataVersion`.

Seller signals have additional requirements, as the `trustedScoringSignalsURL` is provided by a
context that is not required to be same-origin with the seller:
1. The seller script must provide an `Ad-Auction-Allow-Trusted-Scoring-Signals-From` response header,
a [structured headers list of strings](https://www.rfc-editor.org/rfc/rfc8941) describing origins
from which fetching trusted signals is permitted. The trusted scoring signals fetch may not begin
until this header is received, in order to avoid leaking bid information to a third party.
This means using a cross-origin trusted server for seller information may carry a peformance
penalty.
2. The fetch is a cross-origin [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) fetch
with `Origin:` set to the seller script's origin.
3. The value is passed to `crossOriginTrustedSignals` parameter, not the `trustedScoringSignals`
parameter, and there is one more level of nesting denoting the server's origin, e.g:

```
{
'https://www.kv-server.example': {
'renderURL': {'https://cdn.com/render_url_of_bidder': arbitrary_value_from_signals},
'adComponentRenderURLs': {
'https://cdn.com/ad_component_of_a_bid': arbitrary_value_from_signals,
'https://cdn.com/another_ad_component_of_a_bid': arbitrary_value_from_signals,
...}
}
}
```
4. The data version is passed in `browserSignals.crossOriginDataVersion`, not
`browserSignals.dataVersion`.

Note that older versions of Chrome did not support cross-origin trusted signals. You can query
whether support is available as:

```
navigator.protectedAudience && navigator.protectedAudience.queryFeatureSupport(
"permitCrossOriginTrustedSignals")
```

#### 3.2 On-Device Bidding

Once the trusted bidding signals are fetched, each interest group's bidding function will run, inside a bidding worklet associated with the interest group owner's domain. The buyer's JavaScript is loaded from the interest group's `biddingLogicURL`, which must expose a `generateBid()` function:


```
generateBid(interestGroup, auctionSignals, perBuyerSignals,
trustedBiddingSignals, browserSignals, directFromSellerSignals) {
trustedBiddingSignals, browserSignals, directFromSellerSignals,
crossOriginTrustedSignals) {
...
return {'ad': adObject,
'adCost': optionalAdCost,
Expand All @@ -797,7 +873,7 @@ The arguments to `generateBid()` are:
* `priority` and `prioritySignalsOverrides` are not included. They can be modified by `generatedBid()` calls, so could theoretically be used to create a cross-site profile of a user accessible to `generateBid()` methods, otherwise.
* auctionSignals: As provided by the seller in the call to `runAdAuction()`. This is the opportunity for the seller to provide information about the page context (ad size, publisher ID, etc), the type of auction (first-price vs second-price), and so on.
* perBuyerSignals: The value for _this specific buyer_ as taken from the auction config passed to `runAdAuction()`. This can include contextual signals about the page that come from the buyer's server, if the seller is an SSP which performs a real-time bidding call to buyer servers and pipes the response back, or if the publisher page contacts the buyer's server directly. If so, the buyer may wish to check a cryptographic signature of those signals inside `generateBid()` as protection against tampering.
* trustedBiddingSignals: An object whose keys are the `trustedBiddingSignalsKeys` for the interest group, and whose values are those returned in the `trustedBiddingSignals` request.
* trustedBiddingSignals: An object whose keys are the `trustedBiddingSignalsKeys` for the interest group, and whose values are those returned in the `trustedBiddingSignals` request. This used when the trusted server is same-origin with the buyer's script.
* browserSignals: An object constructed by the browser, containing information that the browser knows, and which the buyer's auction script might want to use or verify. The `dataVersion` field will only be present if the `Data-Version` header was provided and had a consistent value for all of the trusted bidding signals server responses used to construct the trustedBiddingSignals. `topLevelSeller` is only present if `generateBid()` is running as part of a component auction. Additional fields can include information about both the context (e.g. the true hostname of the current page, which the seller could otherwise lie about) and about the interest group itself (e.g. times when it previously won the auction, to allow on-device frequency capping). Note that unlike for `reportWin()` the `joinCount` and `recency` in `generateBid()`'s browser signals *isn't* subject to the [noising and bucketing scheme](#521-noised-and-bucketed-signals). Furthermore, `recency` in `generateBid()`'s browser signals is specified in milliseconds, rounded to the nearest 100 milliseconds.
```
{ 'topWindowHostname': 'www.example-publisher.com',
Expand All @@ -820,6 +896,12 @@ The arguments to `generateBid()` are:
* directFromSellerSignals is an object that may contain the following fields:
* perBuyerSignals: Like auctionConfig.perBuyerSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?perBuyerSignals=[origin]`.
* auctionSignals: Like auctionConfig.auctionSignals, but passed via the [directFromSellerSignals](#25-additional-trusted-signals-directfromsellersignals) mechanism. These are the signals whose subresource URL ends in `?auctionSignals`.
* crossOriginTrustedSignals: Like `trustedBiddingSignals`, but used when the trusted-server is
cross-origin to the buyer's script. The value is an object that has as a key the trusted
server's origin, e.g. `"https://www.kv-server.example"`, and as value an object in format
`trustedBiddingSignals` uses. See
[3.1.1 Cross-Origin Trusted Server Signals](#311-cross-origin-trusted-server-signals) for more
details.

In the case of component auctions, an interest group's `generateBid()` function will be invoked in all component auctions for which it qualifies, though the `bidCount` value passed to future auctions will only be incremented by one for participation in that auction as a whole.

Expand Down
42 changes: 41 additions & 1 deletion PA_Feature_Detecting.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ beacon, and then the ad frame can set the same automatic beacon data for both ev
`top_navigation_commit` and `top_navigation` beacons, and filter out duplicate beacons that have the same exact data.

## Increase in limit to number of component ads
[Intent to Ship](TBD)
[Intent to Ship](https://groups.google.com/a/chromium.org/g/blink-dev/c/3RUQk0GCC9Q/m/wmbXOOB8AAAJ)

Inside `generateBid` one can determine the currently active limit on number of components ads as follows:
```
Expand Down Expand Up @@ -106,14 +106,54 @@ const reportingTimeoutEnabled = navigator.protectedAudience ?
```

## Returning multiple bids from generateBid()
[Intent to Ship](https://groups.google.com/a/chromium.org/g/blink-dev/c/ZdZXN1D-MtI/)

Inside `generateBid()`, if `browserSignals.multiBidLimit` exists then returning
an array of bids is supported. The value of `browserSignals.multiBidLimit`
returns the maximum numbers of bids that can be returned, which may be as low as
1.

## Component ad subsetting with targetNumAdComponents
[Intent to Ship](https://groups.google.com/a/chromium.org/g/blink-dev/c/ZdZXN1D-MtI/)

Inside `generateBid()`, if `browserSignals.multiBidLimit` exist then
the `targetNumAdComponents` and `numMandatoryAdComponents` bid fields will be
considered.

## Cross-origin trusted signals
[Intent to Ship](TBD)

From context of a web page:
```
navigator.protectedAudience && navigator.protectedAudience.queryFeatureSupport(
"permitCrossOriginTrustedSignals")
```

## Getting browser-side detectable features as an object
Sometimes it's desirable to get status of all features detectable via `queryFeatureSupport` in a
forward-compatible way. Sufficiently recent versions provide this functionality via
`queryFeatureSupport('*')`, which returns a dictionary describing state of various features. Since
that functionality isn't available in older versions, backwards-compatibility polyfilling is
suggested:

```
let qfs = navigator.protectedAudience ?
navigator.protectedAudience.queryFeatureSupport.bind(navigator.protectedAudience) : null;
let allFeatureStatus = qfs ?
(qfs("*") || {
adComponentsLimit: qfs("adComponentsLimit"),
deprecatedRenderURLReplacements: qfs("deprecatedRenderURLReplacements"),
reportingTimeout: qfs("reportingTimeout")
}) : {}
```

An example return value would be:
```
{
"adComponentsLimit":40,
"deprecatedRenderURLReplacements":false,
"reportingTimeout":true,
"permitCrossOriginTrustedSignals":true
}
```

0 comments on commit 38d3b02

Please sign in to comment.