Skip to content

Commit

Permalink
Add iframe support for adAuctionHeaders to explainer. (WICG#887)
Browse files Browse the repository at this point in the history
* Remove `reportAdditionalBidResult` for additional bids.

In the most recent version of the additional bids/negative targeting
design, additional bids are transported via HTTP response headers, so
that sellers don't have a risk for which they'd need a differently named
reporting function to acknowledge that risk. The text in the explainer
correctly noted the risk to buyers, and the differently named reporting
function for buyers, `reportAdditionalBidWin`, remains.

* Add iframe support for adAuctionHeaders to explainer.

This support is provided by a new `adAucitonsHeader` on the iframe attribute that will have the same functional behavior as the `adAuctionHeaders` fetch flag, in that it will trigger the user agent to send the `Sec-Ad-Auction-Fetch` request header, and to remove `Ad-Auction-Signals` and `Ad-Auction-Additional-Bid` response headers, providing their values to the Protected Audience auction.

* Add timing and B&A response blobs for iframe adAuctionHeaders.

Add a few sentences to clarify when Promises should be resolved when
using both fetch and iframe mechanisms for adAuctionHeaders.

Also added a paragraph to the B&A explainer noting the potential use of
iframe navigation to retrieve response blobs.

* Clarify difference between additional bids and directFromSellerSignals.

* Adjust wording for iframe support for Ad-Auction-Result headers.

This is a slight adjustment in wording on the B&A explainer for clarity.

* Clarify guidance on response headers received before runAdAuction.

Specifically, we clarify here that the `directFromSellerSignals` should
be provided as a non-Promise in that scenario, versus as a Promise
that's immediately resolved.

* Inline the guidance for adAuctionHeaders fetch flag/iframe attribute.

For additional bids, this document previously pointed to the
directFromSellerSignals section for details on how to use the
`adAuctionHeaders` fetch flag or iframe attribute to use response
header interception. To reduce confusion (at the cost of some
repetition), this version copies some of that guidance into the
additional bids section.

* Update B&A response blob URL on iframe to match that of fetch request.

* Removing extraneous line left behind from a copy/paste error

* Replace the term 'parameter' with 'field' for auction config fields
  • Loading branch information
orrb1 authored Dec 21, 2023
1 parent d512d45 commit 916fb56
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 9 deletions.
42 changes: 33 additions & 9 deletions FLEDGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -527,15 +527,25 @@ For the JSON response, only the `https` scheme is supported -- the `uuid-in-pack
#### 2.5.2 Using Response Headers
An alternative way to pass DirectFromSellerSignals without subresource bundles is via the `Ad-Auction-Signals` response header of some `fetch()` request, together with the `directFromSellerSignalsHeaderAdSlot` parameter on `navigator.runAdAuction()`.
An alternative way to pass DirectFromSellerSignals without subresource bundles is via the `Ad-Auction-Signals` response header of some `fetch()` request or `iframe` navigation, together with the `directFromSellerSignalsHeaderAdSlot` field on `navigator.runAdAuction()`.
With this method, a [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) call is made by some script on the page (this call may be made in a subframe), with an extra option, `{adAuctionHeaders: true}`:
To pass DirectFromSellerSignals using a [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) call made by some script on the page (including in a subframe), specify an extra option, `{adAuctionHeaders: true}`:
```javascript
let fetchResponse = await fetch("https://seller.com/signals", {adAuctionHeaders: true});
```

The browser will make the request it would without `{adAuctionHeaders: true}`, with the exception that the request will also include a request header, `Sec-Ad-Auction-Fetch: ?1`. This header indicates to the server that any `Ad-Auction-Signals` response header from the server will only be loaded in auctions via `directFromSellerSignalsHeaderAdSlot` (this is analogous to the guarantees of `Ad-Auction-Only` and `Sec-Fetch-Dest: webbundle` from the [subresource bundle version](#251-using-subresource-bundles) -- scripts on the page cannot set the `Sec-Ad-Auction-Fetch: ?1` request header without using the `{adAuctionHeaders: true}` option).
The script must resolve the `directFromSellerSignalsHeaderAdSlot` Promise only after the response for this call has been received. If the script chooses to call `runAdAuction()` after this response is received, `directFromSellerSignalsHeaderAdSlot` can be specified directly without a Promise.

To pass DirectFromSellerSignals using an [`iframe`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) navigation, specify the `adAuctionHeaders` attribute on the `iframe` element:

```html
<iframe src="https://seller.com/signals" adAuctionHeaders></iframe>
```

If script that invokes `runAdAuction()` is part of the response to that iframe navigation, `directFromSellerSignalsHeaderAdSlot` can be specified directly without a Promise because `runAdAuction()` cannot be called until after the response - with its DirectFromSellerSignals headers - has been received.

The browser will make the request for either the `fetch()` or the `iframe` navigation that it otherwise would, with the exception that the request will also include a request header, `Sec-Ad-Auction-Fetch: ?1`. This header indicates to the server that any `Ad-Auction-Signals` response header from the server will only be loaded in auctions via `directFromSellerSignalsHeaderAdSlot` (this is analogous to the guarantees of `Ad-Auction-Only` and `Sec-Fetch-Dest: webbundle` from the [subresource bundle version](#251-using-subresource-bundles) -- scripts on the page cannot set the `Sec-Ad-Auction-Fetch: ?1` request header without using the `{adAuctionHeaders: true}` option).

The value of the `Ad-Auction-Signals` header must be JSON formatted, with the following schema:

Expand All @@ -560,7 +570,7 @@ When invoking `navigator.runAdAuction()`, `directFromSellerSignalsHeaderAdSlot`

The JSON will be parsed by the browser, and passed via the same `directFromSellerSignals` worklet functions parameter as in [the subresource bundle](#251-using-subresource-bundles) version of DirectFromSellerSignals, with `sellerSignals` only being delivered to the seller, `perBuyerSignals` only being delivered to the buyer for each buyer origin key, and `auctionSignals` being delivered to all parties. Since the top-level JSON value is an array, multiple `adSlot` responses may be set for a given `Ad-Auction-Signals` header. In the dictionary with the `adSlot`, the `sellerSignals`, `auctionSignals`, and `perBuyerSignals` fields are optional -- they will be passed as null if not specified.

Since both `directFromSellerSignals` and `directFromSellerSignalsHeaderAdSlot` (the parameters on `navigator.runAdAuction()`) set the same `directFromSellerSignals` parameter on the worklet functions, it is not valid to use both `directFromSellerSignals` and `directFromSellerSignalsHeaderAdSlot` in the same auction. However, component auctions in the same top-level auction / the top-level itself do not all need to use the same type of DirectFromSellerSignals (and it's also valid if only some component auctions / the top-level use DirectFromSellerSignals).
Since both `directFromSellerSignals` and `directFromSellerSignalsHeaderAdSlot` (the fields on `navigator.runAdAuction()`) set the same `directFromSellerSignals` parameter on the worklet functions, it is not valid to use both `directFromSellerSignals` and `directFromSellerSignalsHeaderAdSlot` in the same auction. However, component auctions in the same top-level auction / the top-level itself do not all need to use the same type of DirectFromSellerSignals (and it's also valid if only some component auctions / the top-level use DirectFromSellerSignals).

Failure to find a matching `adSlot` results in the fields of the `directFromSellerSignals` object passed to worklet functions being set to null, similar to the [subresource bundle version](#251-using-subresource-bundles).

Expand Down Expand Up @@ -1026,7 +1036,7 @@ Each additional bid may provide a value for **at most** one of the `negativeInte
The `auctionNonce`, `seller`, and `topLevelSeller` fields are used to prevent replay of this additional bid. The `auctionNonce` is described below in section [6.1 Auction Nonce](#61-auction-nonce). The `seller` and `topLevelSeller` fields echo those present in the `browserSignals` argument to `generateBid()` as described in section [3.2 On-Device Bidding](#32-on-device-bidding). In `generateBid()`, these are meant to ensure that the buyer acknowledges and accepts that their bid can participate in an auction with those parties. Additional bids don't have a corresponding call to `generateBid()`, and so the `seller` and `topLevelSeller` fields in an additional bid are intended to allow for the same acknowledgement as those in `browserSignals`.
Additional bids are not provided through the auction config passed to `runAdAuction()`, but rather through the response headers of a Fetch request, as described below in section [6.3 HTTP Response Headers](#63-http-response-headers). However, the auction config still has an `additionalBids` field, which is a Promise with no value, used only to signal to the auction that the additional bids have arrived and are ready to be accepted in the auction. For each additional bid, its owner must be included in interestGroupBuyers for that additional bid to participate in the auction.
Additional bids are not provided through the auction config passed to `runAdAuction()`, but rather through the response headers of a Fetch request or `iframe` navigation, as described below in section [6.3 HTTP Response Headers](#63-http-response-headers). However, the auction config still has an `additionalBids` field, which is a Promise with no value, used only to signal to the auction that the additional bids have arrived and are ready to be accepted in the auction. For each additional bid, its owner must be included in interestGroupBuyers for that additional bid to participate in the auction.
```
navigator.runAdAuction({
Expand Down Expand Up @@ -1138,20 +1148,34 @@ Note that the key fields are used by the browser both to verify the signature, a
The browser ensures, using TLS, the authenticity and integrity of information provided to the auction through calls made directly to an ad tech's servers. This guarantee is not provided for data passed in `runAdAuction()`. To account for this, additional bids use the same HTTP response header interception mechanism that's already in use for the [Bidding & Auction response blob](FLEDGE_browser_bidding_and_auction_API.md#step-3-get-response-blobs-to-browser) and `directFromSellerSignals`.
To use HTTP response headers to convey the additional bids, the request to fetch them will first need to specify the `adAuctionHeaders` fetch flag.
Servers return additional bids to the browser using the `Ad-Auction-Additional-Bid` response header of some `fetch()` request or `iframe` navigation, together with the `additionalBids` field on `navigator.runAdAuction()`. This uses the same syntax as that used to convey `directFromSellerSignals` [using response headers](#252-using-response-headers).
To request additional bids using a [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) call made by some script on the page (including in a subframe), specify an extra option, `{adAuctionHeaders: true}`:
```javascript
let fetchResponse = await fetch("https://...", {adAuctionHeaders: true});
```
fetch("https://...", {adAuctionHeaders: true});

The script must resolve the `additionalBids` Promise only after the response for this call has been received. If the script chooses to call `runAdAuction()` after this response is received, the `additionalBids` Promise may be immediately resolved.

To request additional bids using an [`iframe`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) navigation, specify the `adAuctionHeaders` attribute on the `iframe` element:

```html
<iframe src="https://..." adAuctionHeaders></iframe>
```

This signals to the browser that it should look for one or more additional bids encoded as HTTP response headers from this Fetch. Each instance of the `Ad-Auction-Additional-Bid` response header will correspond to a single additional bid. The response may include more than one additional bid by specifying multiple instances of the `Ad-Auction-Additional-Bid` response header. The structure of each instance of the `Ad-Auction-Additional-Bid` header must be as follows:
If script that invokes `runAdAuction()` is part of the response to that iframe navigation, the `adAuctionHeaders` Promise may be immediately resolved from within the iframe because `runAdAuction()` cannot be called until after the response - with its additional bid headers - has been received.

The browser will make the request for either the Fetch or the `iframe` navigation that it otherwise would, with the exception that the request will also include a request header, `Sec-Ad-Auction-Fetch: ?1`. This header indicates to the server that each `Ad-Auction-Additional-Bid` response header from the server will be decoded as an additional bid and loaded into the auction. Each instance of the `Ad-Auction-Additional-Bid` response header will correspond to a single additional bid. The response may include more than one additional bid by specifying multiple instances of the `Ad-Auction-Additional-Bid` response header. The structure of each instance of the `Ad-Auction-Additional-Bid` header must be as follows:

```
Ad-Auction-Additional-Bid:
<auction nonce>:<base64-encoding of the signed additional bid>
```

These HTTP response headers are intercepted by the browser and diverted to participate in the auction without passing through the JavaScript context. When all of the additional bids for an auction have been received this way, the seller should resolve the `additionalBids` Promise passed into the auctionConfig that was described in section [6. Additional Bids](#6-additional-bids). The browser will use this as the signal that it's ready to accept the bids provided by the `Ad-Auction-Additional-Bid` response headers into the auction.
The browser uses the auction nonce prefix from each response header to associate each additional bid to its corresponding auction. For single-seller auctions, this maps to a particular call to `runAdAuction()`, whereas for multi-seller auctions, this maps to a particular component auction.

All `Ad-Auction-Additional-Bid` response headers are intercepted by the browser and diverted to participate in the auction without passing through the JavaScript context. When all of the additional bids for an auction have been received this way, the seller should resolve the `additionalBids` Promise passed as described above. The browser will use this as the signal that it has all of the additional bids intended for this auction.

#### 6.4 Reporting Additional Bid Wins

Expand Down
5 changes: 5 additions & 0 deletions FLEDGE_browser_bidding_and_auction_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ fetch('https://www.example-ssp.com/auction', { <b>adAuctionHeaders: true</b>,
</pre>
Note that `adAuctionHeaders` only works with HTTPS requests.

Response blobs can also be retrieved using an `iframe` navigation by specifying the `adAuctionHeaders` attribute on the iframe element. As with the Fetch flag, the `adAuctionHeaders` iframe attribute prepares the browser to look for `Ad-Auction-Result` HTTP response headers:
```html
<iframe src="https://www.example-ssp.com/auction" adAuctionHeaders></iframe>
```

For each response blob sent back to the browser, the seller’s server attaches a response header containing the base64url encoded (RFC 4648 section 5) SHA-256 hash of the response blob:

```
Expand Down

0 comments on commit 916fb56

Please sign in to comment.