Code change:
Before the client can upload its report to the leader, it must know the public key of each of the aggregators.  These are retrieved from <del> each aggregator by sending a request to "[aggregator]/hpke_config", where "[aggregator]" is the aggregator's endpoint URL, obtained from the task parameters.  The aggregator responds to well-formed requests with status 200 and an "HpkeConfig" value: </del> <ins> each aggregator by sending a request to "[aggregator]/hpke_config?task_id=[task-id]", where "[aggregator]" is the aggregator's endpoint URL, obtained from the task parameters, and "[task-id]" is the task ID obtained from the task parameters, encoded in Base 64 with URL and filename safe alphabet with no padding, as specified in sections 5 and 3.2 of RFC4648.  If the aggregator does not recognize the task ID, then it responds with HTTP error status 404 Not Found and an error of type "unrecognizedTask".  The aggregator responds to well-formed requests with status 200 and an "HpkeConfig" value: [TODO: Allow aggregators to return HTTP 403 Forbidden in deployments that use authentication to avoid leaking information about which tasks exist.] </ins> [OPEN ISSUE: Decide whether to expand the width of the id, or support multiple cipher suites (a la OHTTP/ECH).]

Related discussion:
text: All protocol request messages contain a field, which allows aggregators to service multiple tasks from a single set of endpoints. The exception is : since it is an HTTP GET request, there is no body, and thus no place for the client to indicate the desired to the aggregator. We don't want to introduce a request body to , because then it would have to be a POST instead of a GET, and that would make it harder for implementations to cache HPKE config values. So instead we have clients encode the task ID in RFC 4648 Base16 (a.k.a. hexadecimal) and provide it as a query parameter. See issue
My goal here is to enable our aggregator implementations in the interop target to use one HPKE config per task. The alternative to this would be for us to use aggregator endpoints that somehow incorporate the task ID, as I described , which is already permitted by the spec as written.
The Base64 alphabet includes , and , which means you have to URL encode (a.k.a. percent encode) Base64 strings before you can use them in a URL, which is a chore and yields less readable URLs (not that 64 character hex strings is especially user-friendly). An alternative would be to use RFC 4648's , omitting the padding characters as suggested in since task IDs are of a known length.
Gotcha. I think the main thing is to be consistent. I would either: Change this PR to use base64url; or Tack on a commit that makes all encodings of the taskID (except those that appear in the body, of course) the same (i.e., hexadecimal). I think (2.) would be my preference.
I agree with the consistency argument. I'm leaning towards using everywhere because it's more compact than Base16/hex, and also I think implementations are less likely to be surprised by case requirements in base64url (i.e., it's obvious that base64 is case sensitive, but you have to read RFC 4648 attentively to notice that it mandates uppercase hex strings).
Base64Url sounds good to me. I took a quick look and it appears that most standard base64 libraries also support the URL encoding.
I will clean this up and merge it once I have implemented it in Janus and convinced myself it's sound.
SGTM, but why not base64 encode the taskID for consistency with URL