Issuer name, identifying the Issuer.  This is typically a host name that can be used to construct HTTP requests to the Issuer. <del> Issuer Public Key pkI, with a key identifier "key_id" computed as described in issuer-configuration. </del>  Challenge value "challenge", an opaque byte string.  For example, this might be provided by the redemption protocol in HTTP- "token_type" is a 2-octet integer, which matches the type in the challenge. <del> "token_key_id" is the least significant byte of the "key_id" in network byte order (in other words, the last 8 bits of "key_id"). </del>  "blinded_msg" is the Ne-octet blinded message defined above, computed as "SerializeElement(blinded_element)".  Ne is as defined The TokenRequest contains a supported token_type. <del> The TokenRequest.token_key_id corresponds to a key ID of a Public Key owned by the issuer. </del>  The TokenRequest.blinded_request is of the correct size. denoted skI and pkI, respectively, used to produce tokens.  Each key pair MUST be generated as follows: <del> The key identifier for this specific key pair, denoted "key_id", is computed as follows: </del>  6. Issuer name, identifying the Issuer.  This is typically a host name that can be used to construct HTTP requests to the Issuer. <del> Issuer Public Key pkI, with a key identifier "key_id" computed as described in public-issuer-configuration. </del>  Challenge value "challenge", an opaque byte string.  For example, this might be provided by the redemption protocol in HTTP- "token_type" is a 2-octet integer, which matches the type in the challenge. <del> "token_key_id" is the least significant byte of the "key_id" in network byte order (in other words, the last 8 bits of "key_id"). </del>  "blinded_msg" is the Nk-octet request defined above. The TokenRequest contains a supported token_type. <del> The TokenRequest.token_key_id corresponds to a key ID of a Public Key owned by the issuer. </del>  The TokenRequest.blinded_msg is of the correct size. denoted skI and pkI, respectively, used to produce tokens.  Each key pair SHALL be generated as as specified in FIPS 186-4 DSS. <del> The key identifier for a keypair (skI, pkI), denoted "key_id", is computed as SHA256(encoded_key), where encoded_key is a DER-encoded SubjectPublicKeyInfo (SPKI) object carrying pkI.  The SPKI object MUST use the RSASSA-PSS OID RFC5756, which specifies the hash </del>  algorithm and salt size.  The salt size MUST match the output size of the hash function associated with the public key and token type.  7. This document outlines how to instantiate the Issuance protocol based <del> on the VOPRF defined in OPRF and blind RSA protocol defnied in BLINDRSA.  All security considerations described in the VOPRF document also apply in the Privacy Pass use-case.  Considerations related to broader privacy and security concerns in a multi-Client and multi-Issuer setting are deferred to the Architecture document I- D.ietf-privacypass-architecture. </del>  8.

cc NAME NAME
Let's use different names to make this distinction clear.
This helps, thanks!

Issuer name, identifying the Issuer.  This is typically a host name that can be used to construct HTTP requests to the Issuer.  <ins> Issuer Public Key pkI, with a key identifier "token_key_id" computed as described in issuer-configuration. </ins> Challenge value "challenge", an opaque byte string.  For example, this might be provided by the redemption protocol in HTTP- "token_type" is a 2-octet integer, which matches the type in the challenge.  <ins> "truncated_token_key_id" is the least significant byte of the "token_key_id" in network byte order (in other words, the last 8 bits of "token_key_id"). </ins> "blinded_msg" is the Ne-octet blinded message defined above, computed as "SerializeElement(blinded_element)".  Ne is as defined The TokenRequest contains a supported token_type.  <ins> The TokenRequest.truncated_token_key_id corresponds to the truncated key ID of a Public Key owned by the issuer. </ins> The TokenRequest.blinded_request is of the correct size. denoted skI and pkI, respectively, used to produce tokens.  Each key pair MUST be generated as follows:  <ins> The key identifier for this specific key pair, denoted "token_key_id", is computed as follows: Since Clients truncate "token_key_id" in each "TokenRequest", Issuers should ensure that the truncated form of new key IDs do not collide with other truncated key IDs in rotation. </ins> 6. Issuer name, identifying the Issuer.  This is typically a host name that can be used to construct HTTP requests to the Issuer.  <ins> Issuer Public Key pkI, with a key identifier "token_key_id" computed as described in public-issuer-configuration. </ins> Challenge value "challenge", an opaque byte string.  For example, this might be provided by the redemption protocol in HTTP- "token_type" is a 2-octet integer, which matches the type in the challenge.  <ins> "truncated_token_key_id" is the least significant byte of the "token_key_id" in network byte order (in other words, the last 8 bits of "token_key_id"). </ins> "blinded_msg" is the Nk-octet request defined above. The TokenRequest contains a supported token_type.  <ins> The TokenRequest.truncated_token_key_id corresponds to the truncated key ID of a Public Key owned by the issuer. </ins> The TokenRequest.blinded_msg is of the correct size. denoted skI and pkI, respectively, used to produce tokens.  Each key pair SHALL be generated as as specified in FIPS 186-4 DSS.  <ins> The key identifier for a keypair (skI, pkI), denoted "token_key_id", is computed as SHA256(encoded_key), where encoded_key is a DER- encoded SubjectPublicKeyInfo (SPKI) object carrying pkI.  The SPKI object MUST use the RSASSA-PSS OID RFC5756, which specifies the hash </ins> algorithm and salt size.  The salt size MUST match the output size of the hash function associated with the public key and token type. <ins> Since Clients truncate "token_key_id" in each "TokenRequest", Issuers should ensure that the truncated form of new key IDs do not collide with other truncated key IDs in rotation. </ins> 7. This document outlines how to instantiate the Issuance protocol based  <ins> on the VOPRF defined in OPRF and blind RSA protocol defined in BLINDRSA.  All security considerations described in the VOPRF and blind RSA documents also apply in the Privacy Pass use-case. Considerations related to broader privacy and security concerns in a multi-Client and multi-Issuer setting are deferred to the Architecture document I-D.ietf-privacypass-architecture. Beyond these considerations, it is worth highlighting the fact that Client TokenRequest messages contain truncated token key IDs.  This is done to minimize the chance that an Issuer can use distinct keys for targeting specific users.  Since the key ID is truncated to a single byte, an Issuer can partition the set of Clients into at most 256 different anonymity sets.  On top of this key ID space, Clients SHOULD apply some form of key consistency mechanism to help ensure they are not being given unique keys; see CONSISTENCY for more details. </ins> 8.


sense that they cannot be linked back to the previous session where they were issued. <del> The Internet performance company Cloudflare has already implemented server-side support for an initial version of the Privacy Pass protocol PPSRV, and a client-side implementations is also available PPEXT.  More recently, a number of applications have been built upon the protocol, or upon slight variants of it; see: TRUST, OpenPrivacy, PrivateStorage.  The protocol can be instantiated using a cryptographic primitive known as a verifiable oblivious pseudorandom function (VOPRF) for implementing the authorization mechanism.  Such VOPRF protocols can be implemented over prime-order groups, and constructions are currently being drafted in separate standardization processes I-D.irtf-cfrg-voprf. </del> The Privacy Pass protocol is split into three stages.  The first stage, initialisation, produces the global server configuration that is broadcast to (and stored by) all clients.  The second stage, the The "ServerConfig" struct describes and maintains the underlying configuration that is used by the server. <del> The "SecretKey" and "PublicKey" types are just wrappers around byte </del>  arrays. 3.1.3. 3.1.6. <del> The "ClientIssuanceMessage" struct corresponds to the message that </del>  the client sends to the server during the issuance phase of the protocol (issuance-phase). client. The value of "n" is determined by the length of the <del> "ClientIssuanceElement" vector in the "ClientIssuanceMessage" struct. The internal data types are described below: </del>  3.1.8. 3.1.9. <del> The "RedemptionMessage" struct consists of the data that is sent by </del>  the client during the redemption phase of the protocol (redemption- phase). 3.1.10. The "ServerRedemptionResponse" struct corresponds to a boolean value <del> that indicates whether the "ClientRedemptionMessage" sent by the </del>  client is valid.  It can also contain any associated data. 3.2. Inputs: <del> "s_cfg": A "ServerConfig" struct. </del>  <del> "issuance_message": A "ClientIssuanceMessage" struct. </del>  Outputs: Outputs: <del> "message": A "ClientRedemptionMessage" struct. </del>  3.2.7. Inputs: <del> "s_cfg": A "ServerConfig" struct. </del>  <del> "message": A "ClientRedemptionMessage" struct. </del>  Outputs:

Rename IssuanceMessage and RedemptionMessage to IssuanceRequest and RedemptionRequest, respectively. Rename SecretKey to PrivateKey. Change to an integer value, rather than opaque vector. I also removed company-specific information, which is not really relevant for the document. (That's useful information, but not appropriate for a standards document, I think.) cc NAME NAME

sense that they cannot be linked back to the previous session where they were issued.  The Privacy Pass protocol is split into three stages.  The first stage, initialisation, produces the global server configuration that is broadcast to (and stored by) all clients.  The second stage, the The "ServerConfig" struct describes and maintains the underlying configuration that is used by the server.  <ins> The "PrivateKey" and "PublicKey" types are just wrappers around byte </ins> arrays. 3.1.3. 3.1.6.  <ins> The "ClientIssuanceRequest" struct corresponds to the message that </ins> the client sends to the server during the issuance phase of the protocol (issuance-phase). client. The value of "n" is determined by the length of the  <ins> "ClientIssuanceElement" vector in the "ClientIssuanceRequest" struct. The internal data types are described below. </ins> 3.1.8. 3.1.9.  <ins> The "RedemptionRequest" struct consists of the data that is sent by </ins> the client during the redemption phase of the protocol (redemption- phase). 3.1.10. The "ServerRedemptionResponse" struct corresponds to a boolean value  <ins> that indicates whether the "ClientRedemptionRequest" sent by the </ins> client is valid.  It can also contain any associated data. 3.2. Inputs:  <ins> "srv_cfg": A "ServerConfig" struct. </ins>  <ins> "issuance_request": A "ClientIssuanceRequest" struct. </ins> Outputs: Outputs:  <ins> "message": A "ClientRedemptionRequest" struct. </ins> 3.2.7. Inputs:  <ins> "srv_cfg": A "ServerConfig" struct. </ins>  <ins> "message": A "ClientRedemptionRequest" struct. </ins> Outputs:


hardness assumptions of the underlying cryptographic protocol(s). The issuance protocol can reveal the Issuer public key for the purposes of determining which private key to use in producing the <del> token.  A result of this property is that the redemption flow is unlinkable from the issuance flow. </del>  One-more forgery security.  The issuance protocol MUST NOT allow malicious Clients or Attesters (acting as Clients) to forge tokens

cc NAME
E.g., consider a protocol where the Issuer signs a commitment to the token challenge. This fails as an unlinkable anonymous credentials because the signature is not randomized, but is has input secrecy because of the commitment.
In this hypothetical example, is the commitment not revealed during redemption? If so, I think we could address this by saying that input secrecy is necessary but insufficient for unlinkability. Thoughts?

hardness assumptions of the underlying cryptographic protocol(s). The issuance protocol can reveal the Issuer public key for the purposes of determining which private key to use in producing the  <ins> token. </ins> One-more forgery security.  The issuance protocol MUST NOT allow malicious Clients or Attesters (acting as Clients) to forge tokens


others may not have this property. Issuer identity.  Tokens identify which Issuers are trusted for a <del> given issuance protocol.  The selected Issuer transitively determines what types of attestation the Origin is willing to accept.  For example, if a given Issuer "issuer.example" has two trusted Attesters, then any Origin choosing "issuer.example" as its Issuer is willing to accept attestation checks done by either of these two Attesters. </del>  Redemption context.  Tokens can be bound to a given redemption context, which influences a client's ability to pre-fetch and

cc NAME
I found this sentence hard to interpret: both because of the use "transitive" and because, AIUI, the Origin does not directly accept attestations at all. I tried to be a bit more explicit in this phrasing:
Good clarification! Please check out the linked PR where I applied a variant of your suggested text.

others may not have this property. Issuer identity.  Tokens identify which Issuers are trusted for a  <ins> given issuance protocol.  Each Issuer, in turn, determines which Attesters it is willing to accept in the issuance protocol.  This means that if an Origin origin.example accepts tokens issued by Issuer issuer.example, and that Issuer in turn accepts different types of attestation from more than one trusted Attester, then a Client may use either of these trusted Attesters to issue and redeem tokens for origin.example.  However, origin.example neither explicitly specifies nor learns the Attesters or their attestation formats used for token issuance. </ins> Redemption context.  Tokens can be bound to a given redemption context, which influences a client's ability to pre-fetch and


types of participants, underlying cryptographic constructions used when issuing tokens, and even privacy properties. <del> Clients initiate the Token issuance protocol using the challenge, a randomly generated nonce, and public key for the Issuer.  The Token issuance protocol itself can be any interactive protocol between </del>  Client, Issuer, or other parties that produces a valid authenticator <del> over the Client's input, subject to the following security </del>  requirements. Unconditional input secrecy.  The issuance protocol MUST NOT

This clarifies the inputs to the issuance protocol as constrained by the current HTTP authentication document. It also notes that these inputs may change in the future to accommodate different issuance protocols and Token formats. cc NAME NAME
The input secrecy requirement suggests that client private input would include the nonce, challenge, but doesn't give any ideas what else might be part of the private input: Why is it important to have a client nonce? Is this something that needs to be spelled out in the architecture document or left to the particular issuance protocol specifications?
The issuance protocol only takes as input the TokenChallenge and client-generated nonce, both of which are considered private. It doesn't take anything else as input. We should just say that directly. A client nonce is a required part of the Token structure.

types of participants, underlying cryptographic constructions used when issuing tokens, and even privacy properties.  <ins> Clients initiate the issuance protocol using the challenge, a randomly generated nonce, and public key for the Issuer, all of which are the Client's private input to the protocol and ultimately bound to an output Token; see Section 2.2. of HTTP-Authentication for details.  Future specifications may change or extend the Client's input to the issuance protocol to produce Tokens with a different structure. The issuance protocol itself can be any interactive protocol between </ins> Client, Issuer, or other parties that produces a valid authenticator  <ins> over the Client's private input, subject to the following security </ins> requirements. Unconditional input secrecy.  The issuance protocol MUST NOT


5.4.  A consequence of limiting the number of participants (Attesters or Issuers) in Privacy Pass deployments for meaningful privacy is that it forces concentrated centralization amongst those participants.{ were chosen.  As a result, clients could have more opportunities to switch between attestation participants. <del> 6. </del>  Beyond the aforementioned security goals for the issuance protocol (issuance-protocol), it is important for Privacy Pass deployments to

cc NAME NAME
The privacy considerations section should probably include a discussion on timing correlation. The timing issues are non-trivial here; in particular, in the scenarios where the token is issued online in response to a token challenge (which is suggested in all of the diagrams, and which is required if the origin requires session-bound tokens). In that case, the anonymity set of issuance flows that could match a redemption flow is limited to those that started after the challenge was sent and ended before the token was redeemed. Even if process takes a second (which seems slow to me), you need a fairly popular issuer service to get a non-trivial anonymity set, and any (obviously desirable) improvements in the latency of this process put further pressure on the anonymity set. I think there should be a caution against deploying PrivacyPass in a setting where the issuance rate can be low, at least in combination with session-bound context.
This is a good suggestion! I proposed text that adds this under the privacy considerations section.

5.4. <ins> Side-channel attacks, such as those based on timing correlation, could be used to link attestation and redemption contexts together. In particular, for interactive tokens that are bound to a Client- specific redemption context, the anonymity set of Clients during the issuance protocol consists of those Clients that started issuance between the time of the Origin's challenge and the corresponding token redemption.  Depending on the number of Clients using a particular Issuer during that time window, the set can be small. Appliations should take such side channels into consideration before choosing a particular deployment model and type of token challenge and redemption context. 6. </ins> A consequence of limiting the number of participants (Attesters or Issuers) in Privacy Pass deployments for meaningful privacy is that it forces concentrated centralization amongst those participants.{ were chosen.  As a result, clients could have more opportunities to switch between attestation participants.  <ins> 7. </ins> Beyond the aforementioned security goals for the issuance protocol (issuance-protocol), it is important for Privacy Pass deployments to


for experimentation with protocols being developed.  Designated experts review, approve, and revoke provisional registrations.  This document defines several Reserved values, which can be used by clients and servers to send "greased" values in token challenges and responses to ensure that implementations remain able to handle

To allow experimentation and private types, define a portion of the token type registry to be reserved for private use.

for experimentation with protocols being developed.  Designated experts review, approve, and revoke provisional registrations. <ins> Values 0xFF00-0xFFFF are reserved for private use, to enable proprietary uses and limited experimentation. </ins> This document defines several Reserved values, which can be used by clients and servers to send "greased" values in token challenges and responses to ensure that implementations remain able to handle


should be deployed to ensure the privacy of clients and the security of all participating entities.  2. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",

[x] 1. The Reference PPEXT is not cited in the document. seems it could be sited in the into PR [x] 2. I think it would be good to explicitly say that the HTTP authentication protocol is targeted at redemption and the issuer protocol is targeted at issuance. PR [ ] 3. Last paragraph in section 3.2.1 mentions Origin Allow Lists. These allow lists are not specifically mentioned earlier in the document. Can you clarify this. [ ] 4. In section 4.3 and 4.4 is the attester involved in the TokeRequest and TokenResponse messages? Is the attester proxying the communication? It would be good to clarify this in the text. [ ] 5. Section 6 has an incomplete reference. [x] 6. It seems that the Reference to RFC 8446 is not needed. PR [ ] 7. The link - URL does not work perhaps this is the updated one? - URL

should be deployed to ensure the privacy of clients and the security of all participating entities. <ins> The privacypass working group is working on HTTP-Authentication as an instantiation of a redemption protocol and ISSUANCE as an instantiation of the issuance protocol. </ins> 2. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",


in attestation quality is therefore a deployment-specific task.  In Split Attester and Issuer deployments (see deploy-split), Issuers can choose to remove compromised Attesters from their trusted set until <del> the compromise is patched, without needing to modify Origin allow- lists. </del>  3.2.2. 4.3. In this model, the Origin and Issuer are operated by the same entity, <del> separate from the Attester, as shown in the figure below. </del>  This model is useful for Origins that require Client-identifying attestation, e.g., through the use of application-layer account 4.4. In this model, the Origin, Attester, and Issuer are all operated by <del> different entities, as shown in the figure below. </del>  This is the most general deployment model, and is necessary for some types of issuance protocols where the Attester plays a role in token A consequence of limiting the number of participants (Attesters or Issuers) in Privacy Pass deployments for meaningful privacy is that <del> it forces concentrated centralization amongst those participants.{ {?CENTRALIZATION=I-D.nottingham-avoiding-internet-centralization}} discusses several ways in which this might be mitigated.  For example, a multi-stakeholder governance model could be established to determine what candidate participants are fit to operate as participants in a Privacy Pass deployment.  This is precisely the system used to control the Web's trust model. </del>  Alternatively, Privacy Pass deployments might mitigate this problem through implementation.  For example, rather than centralize the role

cc NAME
[x] 1. The Reference PPEXT is not cited in the document. seems it could be sited in the into PR [x] 2. I think it would be good to explicitly say that the HTTP authentication protocol is targeted at redemption and the issuer protocol is targeted at issuance. PR [ ] 3. Last paragraph in section 3.2.1 mentions Origin Allow Lists. These allow lists are not specifically mentioned earlier in the document. Can you clarify this. [ ] 4. In section 4.3 and 4.4 is the attester involved in the TokeRequest and TokenResponse messages? Is the attester proxying the communication? It would be good to clarify this in the text. [ ] 5. Section 6 has an incomplete reference. [x] 6. It seems that the Reference to RFC 8446 is not needed. PR [ ] 7. The link - URL does not work perhaps this is the updated one? - URL

in attestation quality is therefore a deployment-specific task.  In Split Attester and Issuer deployments (see deploy-split), Issuers can choose to remove compromised Attesters from their trusted set until  <ins> the compromise is patched. </ins> 3.2.2. 4.3. In this model, the Origin and Issuer are operated by the same entity,  <ins> separate from the Attester, as shown in the figure below.  The Issuer accepts token requests that come from trusted Attesters.  Depending on the issuance protocol, the Attester may relay these requests between Client and Issuer over an authenticated channel, or trust may be established in some other manner. </ins> This model is useful for Origins that require Client-identifying attestation, e.g., through the use of application-layer account 4.4. In this model, the Origin, Attester, and Issuer are all operated by  <ins> different entities, as shown in the figure below.  As with the joint Origin and Issuer model, the Issuer accepts token requests that come from trusted Attesters, and the details of that trust establishment depend on the issuance protocol. </ins> This is the most general deployment model, and is necessary for some types of issuance protocols where the Attester plays a role in token A consequence of limiting the number of participants (Attesters or Issuers) in Privacy Pass deployments for meaningful privacy is that  <ins> it forces concentrated centralization amongst those participants. CENTRALIZATION discusses several ways in which this might be mitigated.  For example, a multi-stakeholder governance model could be established to determine what candidate participants are fit to operate as participants in a Privacy Pass deployment.  This is precisely the system used to control the Web's trust model. </ins> Alternatively, Privacy Pass deployments might mitigate this problem through implementation.  For example, rather than centralize the role


clients. Applications SHOULD constrain tokens to a single origin unless the <del> use case can accommodate such replay attacks. </del>  All random values in the challenge and token MUST be generated using a cryptographically secure source of randomness.

The security considerations of the auth scheme should mention 0-RTT specifically in its discussion of token replay.

clients. Applications SHOULD constrain tokens to a single origin unless the  <ins> use case can accommodate such replay attacks.  Replays are also possible if the client redeems a token sent as part of 0-RTT data. If successful token redemption produces side effects, origins SHOULD implement an anti-replay mechanism to mitigate the harm of such replays.  See RFC8446, Section 8 and RFC9001, Section 9.2 for details about anti-replay mechanisms, as well as RFC8470, Section 3 for discussion about safety considerations for 0-RTT HTTP data. </ins> All random values in the challenge and token MUST be generated using a cryptographically secure source of randomness.


"challenge", which contains a base64url-encoded RFC4648 TokenChallenge value.  Since the length of the challenge is not <del> fixed, the base64url data MUST include padding.  This MUST be unique for every 401 HTTP response to prevent replay attacks. This attribute is required for all challenges. </del>  "token-key", which contains a base64url encoding of the public key for use with the issuance protocol indicated by the challenge. <del> Since the length of the key is not fixed, the base64url data MUST include padding.  This attribute MAY be omitted in deployments where clients are able to retrieve the issuer key using an out-of- band mechanism. </del>  "max-age", an optional attribute that consists of the number of seconds for which the challenge will be accepted by the origin. When used for client authorization, the "PrivateToken" authentication scheme defines one parameter, "token", which contains the base64url- encoded Token struct.  Since the length of the Token struct is not <del> fixed, the base64url data MUST include padding.  All unknown or unsupported parameters to "PrivateToken" authentication credentials MUST be ignored. </del>  Clients present this Token structure to origins in a new HTTP request using the Authorization header as follows:

Is this a breaking change? In my reference implementation, I grab everything after the prefix because that's what the spec said to do.
Well, it would break implementations that do not use the generic HTTP auth grammar for challenges/credentials.
So, yes, this is a breaking change then =) Before this change the spec did not specify the grammar precisely.
Well; it said that it is an HTTP auth scheme, and that, by definition, causes specific syntax requirements. OK, let me rephrase this... The spec should say that is uses "#auth-param" (as per URL) and then maybe clarify that this may require quoting base64 encoded fields.
Right, if the padding isn't needed, then it would be OK to not quote. Our implementation does handle receiving the quotes or not correctly, so the spec was out of alignment there. This is the right change to make.
NAME RFC9110 has this to say about encoding: Most of the implementations of authentication headers I've seen do not use any sort of generic parsing components. Now, I've not seen very many, but enough to conclude that people just reimplement whatever parsing is needed based on the auth type. Do you know how common it is for implementations to rely on these "generic" parsing functions? I ask because this change means that servers that were not previously supporting both types of auth-param encodings need to, and there doesn't seem to be any good reason to do so rather than, say, just pick one. If a server is using these generic parsing functions, then they can continue using them. Otherwise, if they're rolling parsing fresh, they have a simpler task at hand. Assuming clients can also easily pick one option, what's the technical reason for wanting to support both?
Apart of not having to rewrite parsers for each scheme? Clients need to use a generic parser, because WWW-A can hold a list of different challenges. To get to the point where a client can pick the "best" challenge, it actually has to consume the full combined field value, and the only way to do that is a parser that is scheme-agnostic.
NAME let me know if this text looks good now
Approved and taking my concerns to this !
Not sure I understand the question. The syntax for the authentication fields is defined in RFC 9110. You really can't change it (while conforming to that spec). All you get to do is naming the scheme and the auth-param names.
My objection is to the syntax in RFC 9110 itself. It's unhelpfully flexible. But I've settled with addressing that syntax elsewhere.
Then your objection is ~25 years late :-).
Heh, I'm aware! :)
Julian pointed out the following:
You seem to be using . The usual method for having multiple drafts in a repo is to just drop multiple files in the root directory. The approach you have works until you try to do CI integration or access more advanced features, like the primitive support that exists for cross-document citations. See for a complete and operational setup.

"challenge", which contains a base64url-encoded RFC4648 TokenChallenge value.  Since the length of the challenge is not  <ins> fixed, the base64url value MUST include padding.  As an Authentication Parameter ("auth-param" from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This challenge value MUST be unique for every 401 HTTP response to prevent replay attacks.  This attribute is required for all challenges. </ins> "token-key", which contains a base64url encoding of the public key for use with the issuance protocol indicated by the challenge.  <ins> Since the length of the key is not fixed, the base64url value MUST include padding.  As an Authentication Parameter ("auth-param" from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This attribute MAY be omitted in deployments where clients are able to retrieve the issuer key using an out-of-band mechanism. </ins> "max-age", an optional attribute that consists of the number of seconds for which the challenge will be accepted by the origin. When used for client authorization, the "PrivateToken" authentication scheme defines one parameter, "token", which contains the base64url- encoded Token struct.  Since the length of the Token struct is not  <ins> fixed, the base64url value MUST include padding.  As an Authentication Parameter ("auth-param" from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  All unknown or unsupported parameters to "PrivateToken" authentication credentials MUST be ignored. </ins> Clients present this Token structure to origins in a new HTTP request using the Authorization header as follows:


by the token_type and corresponding issuance protocol. The authenticator value in the Token structure is computed over the <del> token_type, nonce, context, and token_key_id fields. </del>  When used for client authorization, the "PrivateToken" authentication scheme defines one parameter, "token", which contains the base64url-

Suspect the prose is not aligned with the structure, it says but there is no field in .
Yup, that should say . The name changed.

by the token_type and corresponding issuance protocol. The authenticator value in the Token structure is computed over the  <ins> token_type, nonce, challenge_digest, and token_key_id fields. </ins> When used for client authorization, the "PrivateToken" authentication scheme defines one parameter, "token", which contains the base64url-


challenges with some non-zero probability.  Likewise, origins SHOULD randomly choose to not challenge clients for tokens with some non- zero probability.  Moreover, origins SHOULD include random token <del> types in token challenges with some non-zero probability. </del>  4.

The spec recommends some greasing in Section 3 In section 5.2, several token types are reserved as greased values. Is the expectation really that origins pick "random" token types, or with non-zero global probability across clients, randomly pick from the set of reserved token types?
This should probably read from the list of reserved GREASE values, rather than random token types (the latter can cause interop issues).
Yeah, that sounds good,

challenges with some non-zero probability.  Likewise, origins SHOULD randomly choose to not challenge clients for tokens with some non- zero probability.  Moreover, origins SHOULD include random token  <ins> types, from the Reserved list of "greased" types (defined in token- types), with some non-zero probability. </ins> 4.


protocol to create a signed token. Token challenge: A requirement for tokens sent from an origin to a <del> client, using the "WWW-Authenticate" HTTP header.  This challenge is bound to a specific token issuer and issuance protocol, and may be additionally bound to a specific context or origin name. </del>  Token redemption: An action by which a client presents a token to <del> an origin, using the "Authorization" HTTP header. </del>  2. 2.1. Origins send a token challenge to clients in an "WWW-Authenticate" <del> header with the "PrivateToken" scheme.  This challenge includes a TokenChallenge message, along with information about what keys to use when requesting a token from the issuer. </del>  Origins that support this authentication scheme need to handle the following tasks: Clients can ignore the challenge if the token-key is invalid or otherwise untrusted. <del> The header MAY also include the standard "realm" attribute, if </del>  desired.  Issuance protocols MAY require other attributes. <del> As an example, the WWW-Authenticate header could look like this: </del>  Upon receipt of this challenge, a client uses the message and keys in the issuance protocol indicated by the token_type.  If the Caching and pre-fetching of tokens is discussed in caching. <del> Note that it is possible for the WWW-Authenticate header to include multiple challenges.  This allows the origin to indicate support for different token types, issuers, or to include multiple redemption contexts.  For example, the WWW-Authenticate header could look like this: </del>  Origins should only include challenges for different types of issuance protocols with functionally equivalent properties.  For credentials MUST be ignored. Clients present this Token structure to origins in a new HTTP request <del> using the Authorization header as follows: </del>  For token types that support public verifiability, origins verify the token authenticator using the public key of the issuer, and validate

This one goes out to all the HTTP pedants out there =)
There's a few cases of rather than , which is puts you on HTTP's naughty list

protocol to create a signed token. Token challenge: A requirement for tokens sent from an origin to a  <ins> client, using the "WWW-Authenticate" HTTP header field.  This challenge is bound to a specific token issuer and issuance protocol, and may be additionally bound to a specific context or origin name. </ins> Token redemption: An action by which a client presents a token to  <ins> an origin, using the "Authorization" HTTP header field. </ins> 2. 2.1. Origins send a token challenge to clients in an "WWW-Authenticate"  <ins> header field with the "PrivateToken" scheme.  This challenge includes a TokenChallenge message, along with information about what keys to use when requesting a token from the issuer. </ins> Origins that support this authentication scheme need to handle the following tasks: Clients can ignore the challenge if the token-key is invalid or otherwise untrusted.  <ins> The header field MAY also include the standard "realm" attribute, if </ins> desired.  Issuance protocols MAY require other attributes.  <ins> As an example, the WWW-Authenticate header field could look like this: </ins> Upon receipt of this challenge, a client uses the message and keys in the issuance protocol indicated by the token_type.  If the Caching and pre-fetching of tokens is discussed in caching.  <ins> Note that it is possible for the WWW-Authenticate header field to include multiple challenges.  This allows the origin to indicate support for different token types, issuers, or to include multiple redemption contexts.  For example, the WWW-Authenticate header field could look like this: </ins> Origins should only include challenges for different types of issuance protocols with functionally equivalent properties.  For credentials MUST be ignored. Clients present this Token structure to origins in a new HTTP request  <ins> using the Authorization header field as follows: </ins> For token types that support public verifiability, origins verify the token authenticator using the public key of the issuer, and validate


Different types of authenticators, using different token issuance protocols, can be used as Privacy Pass tokens. <del> This document defines a common HTTP authentication scheme (RFC9110), PrivateToken, that allows clients to redeem various kinds of Privacy Pass tokens. </del>  Clients and relying parties interact using this scheme to perform the token challenge and token redemption flow.  Clients use a token 2. <del> Token redemption is performed using HTTP Authentication (RFC9110), with the scheme "PrivateToken".  Origins challenge clients to present a token from a specific issuer (challenge).  Once a client has received a token from that issuer, or already has a valid token available, it presents the token to the origin (redemption). </del>  2.1. "challenge", which contains a base64url-encoded RFC4648 TokenChallenge value.  Since the length of the challenge is not fixed, the base64url value MUST include padding.  As an <del> Authentication Parameter ("auth-param" from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This challenge value MUST be unique for every 401 HTTP response to prevent replay attacks.  This attribute is required for all challenges. </del>  "token-key", which contains a base64url encoding of the public key for use with the issuance protocol indicated by the challenge. Since the length of the key is not fixed, the base64url value MUST include padding.  As an Authentication Parameter ("auth-param" <del> from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This attribute MAY be omitted in deployments where clients are able to retrieve the issuer key using an out-of-band mechanism. </del>  "max-age", an optional attribute that consists of the number of seconds for which the challenge will be accepted by the origin. scheme defines one parameter, "token", which contains the base64url- encoded Token struct.  Since the length of the Token struct is not fixed, the base64url value MUST include padding.  As an <del> Authentication Parameter ("auth-param" from RFC9110), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  All unknown or unsupported parameters to "PrivateToken" authentication credentials MUST be ignored. </del>  Clients present this Token structure to origins in a new HTTP request using the Authorization header field as follows: This document registers the "PrivateToken" authentication scheme in the "Hypertext Transfer Protocol (HTTP) Authentication Scheme <del> Registry" defined in RFC9110. </del>  Authentication Scheme Name: PrivateToken

Previously, the document linked to RFC 7235, whose whole purpose was to discuss HTTP Authentication. Now you kjust link to RFC 9110, which all of HTTP semantics. Suggest that you link to Section 11 of RFC 9110 to make the reader's life easier.

Different types of authenticators, using different token issuance protocols, can be used as Privacy Pass tokens.  <ins> This document defines a common HTTP authentication scheme (RFC9110, Section 11), PrivateToken, that allows clients to redeem various kinds of Privacy Pass tokens. </ins> Clients and relying parties interact using this scheme to perform the token challenge and token redemption flow.  Clients use a token 2.  <ins> Token redemption is performed using HTTP Authentication (RFC9110, Section 11), with the scheme "PrivateToken".  Origins challenge clients to present a token from a specific issuer (challenge).  Once a client has received a token from that issuer, or already has a valid token available, it presents the token to the origin (redemption). </ins> 2.1. "challenge", which contains a base64url-encoded RFC4648 TokenChallenge value.  Since the length of the challenge is not fixed, the base64url value MUST include padding.  As an  <ins> Authentication Parameter ("auth-param" from RFC9110, Section 11.2), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This challenge value MUST be unique for every 401 HTTP response to prevent replay attacks. This attribute is required for all challenges. </ins> "token-key", which contains a base64url encoding of the public key for use with the issuance protocol indicated by the challenge. Since the length of the key is not fixed, the base64url value MUST include padding.  As an Authentication Parameter ("auth-param"  <ins> from RFC9110, Section 11.2), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  This attribute MAY be omitted in deployments where clients are able to retrieve the issuer key using an out-of-band mechanism. </ins> "max-age", an optional attribute that consists of the number of seconds for which the challenge will be accepted by the origin. scheme defines one parameter, "token", which contains the base64url- encoded Token struct.  Since the length of the Token struct is not fixed, the base64url value MUST include padding.  As an  <ins> Authentication Parameter ("auth-param" from RFC9110, Section 11.2), the value can be either a token or a quoted-string, and might be required to be a quoted-string if the base64url string includes "=" characters.  All unknown or unsupported parameters to "PrivateToken" authentication credentials MUST be ignored. </ins> Clients present this Token structure to origins in a new HTTP request using the Authorization header field as follows: This document registers the "PrivateToken" authentication scheme in the "Hypertext Transfer Protocol (HTTP) Authentication Scheme  <ins> Registry" defined in RFC9110, Section 16.4. </ins> Authentication Scheme Name: PrivateToken


Select the origin information to include in the TokenChallenge. This can be empty to allow fully cross-origin tokens, a single origin name that matches the origin itself, or a list of origin <del> names containing the origin. </del>  The TokenChallenge message has the following structure: the length, in network byte order.  If empty, any non-origin- specific token can be redeemed.  If the string contains multiple origin names, they are delimited with commas "," without any <del> whitespace. </del>  When used in an authentication challenge, the "PrivateToken" scheme uses the following attributes:

Spec says: and and also The sender requirements are implicit. I'm guessing that the sender also MUST include it's own origin name in the non-empty case. Should the spec just state that?

Select the origin information to include in the TokenChallenge. This can be empty to allow fully cross-origin tokens, a single origin name that matches the origin itself, or a list of origin  <ins> names containing the origin itself. </ins> The TokenChallenge message has the following structure: the length, in network byte order.  If empty, any non-origin- specific token can be redeemed.  If the string contains multiple origin names, they are delimited with commas "," without any  <ins> whitespace.  If this field is not empty, the Origin MUST include its own name as one of the names in the list. </ins> When used in an authentication challenge, the "PrivateToken" scheme uses the following attributes:


support, it MUST NOT parse or respond to the challenge.  If the TokenChallenge contains a non-empty origin_info field, the client MUST validate that the name of the origin that issued the <del> authentication challenge is included in the list of origin names. Clients MAY have further restrictions and requirements around validating when a challenge is considered acceptable or valid.  For example, clients can choose to reject challenges that list origin </del>  names for which current connection is not authoritative (according to the TLS certificate).

For example, What happens if validation fails here, is the challenge simply ignored or should the client do something more drastic?

support, it MUST NOT parse or respond to the challenge.  If the TokenChallenge contains a non-empty origin_info field, the client MUST validate that the name of the origin that issued the  <ins> authentication challenge is included in the list of origin names; if validation fails, the client MUST NOT process or respond to the challenge.  Clients MAY have further restrictions and requirements around validating when a challenge is considered acceptable or valid. For example, clients can choose to ignore challenges that list origin </ins> names for which current connection is not authoritative (according to the TLS certificate).


1. Privacy Pass tokens are unlinkable authenticators that can be used to <del> anonymously authorize a client (see ARCHITECTURE).  A client possessing such a token is able to prove that it was able to get a token issued by a token issuer - based on some check from a token issuer, such as authentication or solving a CAPTCHA - without allowing the relying party redeeming the client's token (the origin) to link it with issuance flow. </del>  Different types of authenticators, using different token issuance protocols, can be used as Privacy Pass tokens.

From editor copy today: I found this intro to be a bit clunky. I didn't read the ARCHITECTURE reference yet but don't think that should be a prerequisite to comprehension of the first para. How about something like

1. Privacy Pass tokens are unlinkable authenticators that can be used to  <ins> anonymously authorize a client (see ARCHITECTURE).  Tokens are generated by token issuers, on the basis of authentication, attestation, or some previous action such as solving a CAPTCHA.  A client possessing such a token is able to prove that it was able to get a token issued, without allowing the relying party redeeming the client's token (the origin) to link it with the issuance flow. </ins> Different types of authenticators, using different token issuance protocols, can be used as Privacy Pass tokens.


Public Key: The public key used by the Issuer for issuing and verifying tokens. <del> We assume that all protocol messages are encoded into raw byte format before being sent across the wire. </del>  3.

This is probably just a nitpick but I don't understand what you're assuming here. If the messages are encoded as raw byte format, isn't that really what the document is all about? Maybe what you want to be saying is more like whats in the ?

Public Key: The public key used by the Issuer for issuing and verifying tokens.  <ins> Unless otherwise specified, this document encodes protocol messages in TLS notation from TLS13, Section 3. </ins> 3.


protocol. The Issuer parameters can be obtained from an Issuer via a directory <del> object, which is a JSON object whose values are other JSON objects and URLs for the parameters. </del>  Each "token-keys" JSON object contains the following fields and corresponding raw values. which token key to use based on the order of keys in the list, with preference given to keys earlier in the list. <del> Altogether, the Issuer's JSON directory could look like: </del>  Issuer directory resources have the media type "application/json" and are located at the well-known location /.well-known/token-issuer-

The configuration section lists several requirements that depend on JSON, but a JSON specification is not given. I'm guessing you probably want URL
Issuers MUST provide a configuration , so what spec should they be referring to in order to ensure that this URI is well formed? I started wondering about how percent-encoding might apply, and that got me on to thinking whether you really want to support something like `"issuer-request-uri": "https://EMAIL:123/forum/questions/?tag=networking&order=newest#top",
Unless I'm missing something, I don't think there should be any constraints on how the URI is constructed. We should say something about how it's encoded, though. That's a good point.

protocol. The Issuer parameters can be obtained from an Issuer via a directory  <ins> object, which is a JSON object RFC8259, Section 4 whose values are other JSON values RFC8259, Section 3 for the parameters. </ins> Each "token-keys" JSON object contains the following fields and corresponding raw values. which token key to use based on the order of keys in the list, with preference given to keys earlier in the list.  <ins> Altogether, the Issuer's directory could look like: </ins> Issuer directory resources have the media type "application/json" and are located at the well-known location /.well-known/token-issuer-


5. The Privacy Pass issuance protocol is a two message protocol that <del> takes as input a challenge from the redemption protocol and produces a token, as shown in the figure below. </del>  Issuers provide a Private and Public Key, denoted skI and pkI, respectively, used to produce tokens as input to the protocol.  See computed as described in issuer-configuration. Challenge value "challenge", an opaque byte string.  For example, <del> this might be provided by the redemption protocol in HTTP- Authentication. </del>  Given this configuration and these inputs, the two messages exchanged in this protocol are described below.  This section uses notation computed as described in public-issuer-configuration. Challenge value "challenge", an opaque byte string.  For example, <del> this might be provided by the redemption protocol in HTTP- Authentication. </del>  Given this configuration and these inputs, the two messages exchanged in this protocol are described below. The rsabssa_finalize function is defined in BLINDRSA, Section 5.1.3.. If this succeeds, the Client then constructs a Token as described in <del> HTTP-Authentication as follows: </del>  The Token.nonce value is that which was sampled in private-request. If the rsabssa_finalize function fails, the Client aborts the 8.2. <del> This document updates the "Token Type" Registry with the following values. </del>  8.3.

There's and . I'm guessing these should be collapsed to just one.
table 2 says: -- | -- and Section 8.1 says: What is the Token Type registry and what are the constraints on values in the registry? It's implied that values should be integers but JSON numbers are quite flexible, so would it be valid for me to register e.g. a negative integer. If the "Token Type" registry already exists, I'm not able to find it and a link would be useful. If it doesn't exist and this document wishes to create it, then more work is needed to establish that registry and it's procedures.
We're missing a link to the HTTP auth document, where the registry is defined. Good catch!

5. The Privacy Pass issuance protocol is a two message protocol that  <ins> takes as input a TokenChallenge from the redemption protocol AUTHSCHEME, Section 2.1 and produces a Token AUTHSCHEME, Section 2.2, as shown in the figure below. </ins> Issuers provide a Private and Public Key, denoted skI and pkI, respectively, used to produce tokens as input to the protocol.  See computed as described in issuer-configuration. Challenge value "challenge", an opaque byte string.  For example,  <ins> this might be provided by the redemption protocol in AUTHSCHEME. </ins> Given this configuration and these inputs, the two messages exchanged in this protocol are described below.  This section uses notation computed as described in public-issuer-configuration. Challenge value "challenge", an opaque byte string.  For example,  <ins> this might be provided by the redemption protocol in AUTHSCHEME. </ins> Given this configuration and these inputs, the two messages exchanged in this protocol are described below. The rsabssa_finalize function is defined in BLINDRSA, Section 5.1.3.. If this succeeds, the Client then constructs a Token as described in  <ins> AUTHSCHEME as follows: </ins> The Token.nonce value is that which was sampled in private-request. If the rsabssa_finalize function fails, the Client aborts the 8.2.  <ins> This document updates the "Token Type" Registry from AUTHSCHEME, Section 5.2 with the following values. </ins> 8.3.


Issuer directory resources have the media type "application/json" and are located at the well-known location /.well-known/token-issuer- <del> directory. </del>  4. 8.1.  This document updates the "Token Type" Registry with the following values. <del> 8.2. </del>  This specification defines the following protocol messages, along with their corresponding media types: The definition for each media type is in the following subsections. <del> 8.2.1. </del>  application IESG <del> 8.2.2. </del>  application

While we're here, I'd like to recommend we align the name of this well-known value to align with the request/response names. In particular, what do folks think about "/well-known/private-token-issuer-directory"?
you're probably missing a registration for your well-known in the IANA considerations, the registry is URL

Issuer directory resources have the media type "application/json" and are located at the well-known location /.well-known/token-issuer-  <ins> directory; see wkuri-reg for the registration information for this well-known URI. </ins> 4. 8.1. <ins> This document updates the "Well-Known URIs" Registry WellKnownURIs with the following values. 8.2. </ins> This document updates the "Token Type" Registry with the following values.  <ins> 8.3. </ins> This specification defines the following protocol messages, along with their corresponding media types: The definition for each media type is in the following subsections.  <ins> 8.3.1. </ins> application IESG  <ins> 8.3.2. </ins> application


cryptographic tokens that prove nothing other than that they have been created by a given server in the past ARCHITECTURE. <del> This document describes the issuance protocol for Privacy Pass.  It specifies two variants: one that is privately verifiable based on the oblivious pseudorandom function from OPRF, and one that is publicly verifiable based on the blind RSA signature scheme BLINDRSA. </del>  This document does not cover the Privacy Pass architecture, including choices that are necessary for ensuring that client privacy leaks. The values "token_input" and "blinded_element" are stored locally and used later as described in private-finalize.  The Client then generates an HTTP POST request to send to the Issuer, with the <del> TokenRequest as the body.  The media type for this request is </del>  "application/private-token-request".  An example request is shown below. "concat(SerializeScalar(proof[0]), SerializeScalar(proof[1]))", where Ns is as defined in OPRF, Section 4. <del> The Issuer generates an HTTP response with status code 200 whose body consists of TokenResponse, with the content type set as "application/ private-token-response". </del>  5.3. Upon receipt, the Client handles the response and, if successful, <del> deserializes the body values TokenResponse.evaluate_msg and </del>  TokenResponse.evaluate_proof, yielding "evaluated_element" and "proof".  If deserialization of either value fails, the Client aborts the protocol.  Otherwise, the Client processes the response as "blinded_msg" is the Nk-octet request defined above. The Client then generates an HTTP POST request to send to the Issuer, <del> with the TokenRequest as the body.  The media type for this request is "application/private-token-request".  An example request is shown below, where Nk = 512. </del>  Upon receipt of the request, the Issuer validates the following conditions: The rsabssa_blind_sign function is defined in BLINDRSA, Section 5.1.2..  The Issuer generates an HTTP response with status <del> code 200 whose body consists of TokenResponse, with the content type set as "application/private-token-response". </del>  6.3. Upon receipt, the Client handles the response and, if successful, <del> processes the body as follows: </del>  The rsabssa_finalize function is defined in BLINDRSA, Section 5.1.3.. If this succeeds, the Client then constructs a Token as described in

... I think. I'm double checking to see if there is any other improper HTTP usage.
The Issuance protocol depends on HTTP, so I'd expect this to be cited. Then we get into the HTTP terminology alignment game. For example, where the document says something like should be substituted for as per URL

cryptographic tokens that prove nothing other than that they have been created by a given server in the past ARCHITECTURE.  <ins> This document describes the issuance protocol for Privacy Pass built on HTTP.  It specifies two variants: one that is privately verifiable based on the oblivious pseudorandom function from OPRF, and one that is publicly verifiable based on the blind RSA signature scheme BLINDRSA. </ins> This document does not cover the Privacy Pass architecture, including choices that are necessary for ensuring that client privacy leaks. The values "token_input" and "blinded_element" are stored locally and used later as described in private-finalize.  The Client then generates an HTTP POST request to send to the Issuer, with the  <ins> TokenRequest as the content.  The media type for this request is </ins> "application/private-token-request".  An example request is shown below. "concat(SerializeScalar(proof[0]), SerializeScalar(proof[1]))", where Ns is as defined in OPRF, Section 4.  <ins> The Issuer generates an HTTP response with status code 200 whose content consists of TokenResponse, with the content type set as "application/private-token-response". </ins> 5.3. Upon receipt, the Client handles the response and, if successful,  <ins> deserializes the content values TokenResponse.evaluate_msg and </ins> TokenResponse.evaluate_proof, yielding "evaluated_element" and "proof".  If deserialization of either value fails, the Client aborts the protocol.  Otherwise, the Client processes the response as "blinded_msg" is the Nk-octet request defined above. The Client then generates an HTTP POST request to send to the Issuer,  <ins> with the TokenRequest as the content.  The media type for this request is "application/private-token-request".  An example request is shown below, where Nk = 512. </ins> Upon receipt of the request, the Issuer validates the following conditions: The rsabssa_blind_sign function is defined in BLINDRSA, Section 5.1.2..  The Issuer generates an HTTP response with status  <ins> code 200 whose content consists of TokenResponse, with the content type set as "application/private-token-response". </ins> 6.3. Upon receipt, the Client handles the response and, if successful,  <ins> processes the content as follows: </ins> The rsabssa_finalize function is defined in BLINDRSA, Section 5.1.3.. If this succeeds, the Client then constructs a Token as described in


Reference: Where this algorithm is defined  New entries in this registry are subject to the Specification Required registration policy (RFC8126, Section 4.6).  Designated experts need to ensure that the token type is sufficiently clearly

We need a field to list some extra information about the blind RSA variants. Additional PR incoming for that change.

Reference: Where this algorithm is defined <ins> Notes: Any notes associated with the entry </ins> New entries in this registry are subject to the Specification Required registration policy (RFC8126, Section 4.6).  Designated experts need to ensure that the token type is sufficiently clearly


offering clients an alternative type of challenge such as CAPTCHA for accessing a resource.  To mitigate the risk of deployments becoming dependent on tokens, clients and servers SHOULD grease their behavior unless explicitly configured not to.  In particular, clients SHOULD ignore token

NAME can you give this a quick look and merge if you're OK with it?
I'll just merge it and we can revise if needed
If a server wants to use this auth scheme but the client doesn't support it, what's supposed to happen? Do you have a way for the server to discover that the client does support it?
If the client doesn't support the scheme, it will ignore challenges — this is the same as cases where the client doesn't support a particular token type, or it fails to fetch a token for any reason. This has a useful privacy property in that it doesn't leak information about if the client couldn't fetch a token or if just doesn't support tokens, or chooses not to try to fetch a token.
We do comment on server behavior here:
We can give a simple example where the origin sends a 401 response with a body that is a CAPTCHA, such that clients that don't support this see that instead of using a token.
An example like that would be good, but this makes me wonder: did we ever consider expressing the client's capability to support this token via a CH? I don't remember if we did or not.
I think adding a new fingerprinting surface for that in CH isn't great. There's talk instead of having a javascript capability API for the support.
I don't really think the fingerprinting concern is that significant. If a client supports it, then a server can more than likely (with very high probability) just probe it for a token and confirm its guess. The lack of a hint just makes the server's life more difficult without offering any meaningful privacy improvement to the client. In principle, the less signals the better, but this is a signal that can be determined anyway.
To be clear, I'm not suggesting that we actually propose a CH for this. I'm just raising the thought experiment.

offering clients an alternative type of challenge such as CAPTCHA for accessing a resource. <ins> For example, consider a scenario in which the client is a web browser, and the origin can accept either a token or a solution to a puzzle intended to determine if the client is a real human user.  The origin would send clients a 401 HTTP response that contains a token challenge in a "WWW-Authenticate" header field along with content that contains the puzzle to display to the user.  Clients that are able to respond with a token will be able to automatically return the token and not show the puzzle, while clients that either do not support tokens or are unable to fetch tokens at a particular time can present the user with the puzzle. </ins> To mitigate the risk of deployments becoming dependent on tokens, clients and servers SHOULD grease their behavior unless explicitly configured not to.  In particular, clients SHOULD ignore token


This document specifies two variants of the the two-message issuance protocol for Privacy Pass tokens: one that produces tokens that are privately verifiable, and another that produces tokens that are <del> publicly verifiable.  The privately verifiable issuance protocol optionally supports public metadata during the issuance flow. </del>  1. This section describes a variant of the issuance protocol in private- flow for producing publicly verifiable tokens.  It differs from the <del> previous variant in two important ways: </del>  <del> The output tokens are publicly verifiable by anyone with the Issuer public key. </del>  <del> The issuance protocol does not admit public or private metadata to bind additional context to tokens. The first property means that any Origin can select a given Issuer to produce tokens, as long as the Origin has the Issuer public key, without explicit coordination or permission from the Issuer.  This is because the Issuer does not learn the Origin that requested the token during the issuance protocol. Beyond these differences, the publicly verifiable issuance protocol </del>  variant is nearly identical to the privately verifiable issuance protocol variant.  In particular, Issuers provide a Private and Public Key, denoted skI and pkI, respectively, used to produce tokens

From NAME issuance flow." Where does this metadata come up in the protocol? As far as I can tell, the two protocols look functionally equivalent modulo who can verify. Perhaps you removed metadata at some point? In particular, double check that the following claim in Section 6 is accurate: "The issuance protocol does not admit public or private metadata to bind additional context to tokens."

This document specifies two variants of the the two-message issuance protocol for Privacy Pass tokens: one that produces tokens that are privately verifiable, and another that produces tokens that are  <ins> publicly verifiable. </ins> 1. This section describes a variant of the issuance protocol in private- flow for producing publicly verifiable tokens.  It differs from the  <ins> previous variant in that the output tokens are publicly verifiable by anyone with the Issuer public key. </ins>  <ins> This means any Origin can select a given Issuer to produce tokens, as long as the Origin has the Issuer public key, without explicit coordination or permission from the Issuer.  This is because the Issuer does not learn the Origin that requested the token during the issuance protocol. </ins>  <ins> Beyond this difference, the publicly verifiable issuance protocol </ins> variant is nearly identical to the privately verifiable issuance protocol variant.  In particular, Issuers provide a Private and Public Key, denoted skI and pkI, respectively, used to produce tokens


To verify a token, a verifier checks that Token.authenticator is a valid signature over the remainder of the token input as described <del> below.  The function "RSA-Verify(msg, pk, sig)" is a procedure to verify a signature "sig" over message "msg" using the public key "pk".  Its implementation is not specified in this document. </del>  6.5.

From NAME
This should probably just invoke from RFC8017 directly, since the named variants we allow for this token type must use PSS.

To verify a token, a verifier checks that Token.authenticator is a valid signature over the remainder of the token input as described  <ins> below.  The function "RSASSA-PSS-VERIFY" is defined in Section 8.1.2 of RFC8017, using SHA-384 as the Hash function, MGF1 with SHA-384 as the PSS mask generation function (MGF), and a 48-byte salt length (sLen). </ins> 6.5.


This document specifies two variants of the the two-message issuance protocol for Privacy Pass tokens: one that produces tokens that are <del> privately verifiable, and another that produces tokens that are publicly verifiable. </del>  1. This document describes the issuance protocol for Privacy Pass built on HTTP.  It specifies two variants: one that is privately verifiable <del> based on the oblivious pseudorandom function from OPRF, and one that is publicly verifiable based on the blind RSA signature scheme BLINDRSA. </del>  This document does not cover the Privacy Pass architecture, including choices that are necessary for ensuring that client privacy leaks. verifying tokens. Unless otherwise specified, this document encodes protocol messages <del> in TLS notation from TLS13, Section 3. </del>  3. Issuers MUST provide two parameters for configuration: <del> Issuer Request URI: a token request URL for generating access </del>  tokens.  For example, an Issuer URL might be https://issuer.example.net/example-token-request.  This parameter uses resource media type "text/plain". <del> Issuer Public Key values: an Issuer Public Key for an issuance </del>  protocol. The Issuer parameters can be obtained from an Issuer via a directory 5.4. <del> To verify a token, a verifier creates a VOPRF context, evaluates the token contents, and compares the result against the token authenticator value, as follows: </del>  5.5. 6.4. To verify a token, a verifier checks that Token.authenticator is a <del> valid signature over the remainder of the token input as described below.  The function "RSASSA-PSS-VERIFY" is defined in Section 8.1.2 of RFC8017, using SHA-384 as the Hash function, MGF1 with SHA-384 as the PSS mask generation function (MGF), and a 48-byte salt length (sLen). </del>  6.5.

Hexadecimal constants are used as strings without specifying the length or byte order. For example, "0x0001" might be interpreted in a couple of ways. Usually the correct interpretation is clear in context, but I'm not sure it always is.
[ ] Overall: The document is inconsistent about capitalization after colon (":"). [ ] Abstract: I'm not sure the distinction between public/private verifiability is common knowledge. It might be helpful to say plainly who is doing the verifying. E.g.: "one [variant] providing tokens whose validity can be verified by the issuer only; and another for which token validity can be verified by any party with the issuer public key." [ ] 2 Terminology: "We assume that all protocol messages are encoded into raw byte formatt before being sent across the wire" This doesn't need to be mentioned, in my opinion. [ ] 5.1 Client-To-Issuer Request: The psedocode for computing "client_context" hard-codes a particular OPRF suite (0x0004). Is this the only suite that is permitted/recommended by the document? I don't think this is clear until the token types are defined in Section 8.1. [ ] 5.3 Finalization: Constants hardcoded instructs don't a semi-colon after the constant. (See "Token" in this section, for example.) Is this intentional? It looks a bit odd, and I'm wondering if this is "syntactically" correct. [ ] 5.4 Token Verification: I think it's worth pointing out here that creating the server context requires the Issuer Private Key, which is why VOPRF is not publicly verifiable. [ ] 7 Security Considerations: "All security considerations described in the VOPRF document also apply in the Privacy Pass use-case." What about security considerations for BLINDRSA? It might be a bit cleaner to write something like this: "Each protocol described here inherits the security considerations of its base document: For Section 5, this is [VOPRF]; ... " [ ] Acknowledgements: Sofi is acknowledged, but is also a co-author.
I think I caught all of these. Addressed in . Yes, this is much better! Addressed in . This is addressed by . We explain the constant in the sentence immediately following the pseudocode, so I don't think further clarification is needed. The semi-colon was missing, but we updated this to match what's done in RFC8446. Addressed in . Addressed in . Good catch. This has already been fixed on the editor's branch to say "All security considerations described in the VOPRF and blind RSA documents also apply in the Privacy Pass use-case."

This document specifies two variants of the the two-message issuance protocol for Privacy Pass tokens: one that produces tokens that are  <ins> privately verifiable using the issuance private key, and another that produces tokens that are publicly verifiable using the issuance public key. </ins> 1. This document describes the issuance protocol for Privacy Pass built on HTTP.  It specifies two variants: one that is privately verifiable  <ins> using the issuance private key based on the oblivious pseudorandom function from OPRF, and one that is publicly verifiable using the issuance public key based on the blind RSA signature scheme BLINDRSA. </ins> This document does not cover the Privacy Pass architecture, including choices that are necessary for ensuring that client privacy leaks. verifying tokens. Unless otherwise specified, this document encodes protocol messages  <ins> in TLS notation from TLS13, Section 3.  Moreover, all constants are in network byte order. </ins> 3. Issuers MUST provide two parameters for configuration:  <ins> Issuer Request URI: A token request URL for generating access </ins> tokens.  For example, an Issuer URL might be https://issuer.example.net/example-token-request.  This parameter uses resource media type "text/plain".  <ins> Issuer Public Key values: An Issuer Public Key for an issuance </ins> protocol. The Issuer parameters can be obtained from an Issuer via a directory 5.4.  <ins> To verify a token, a verifier creates a VOPRF context using the Issuer Private Key, evaluates the token contents, and compares the result against the token authenticator value, as follows: </ins> 5.5. 6.4. To verify a token, a verifier checks that Token.authenticator is a  <ins> valid signature over the remainder of the token input using the Issuer Public Key. The function "RSASSA-PSS-VERIFY" is defined in Section 8.1.2 of RFC8017, using SHA-384 as the Hash function, MGF1 with SHA-384 as the PSS mask generation function (MGF), and a 48-byte salt length (sLen). </ins> 6.5.


defined in ARCHITECTURE. Unless otherwise specified, this document encodes protocol messages <del> in TLS notation from TLS13, Section 3.  Moreover, all constants are </del>  in network byte order. 3. (AUTHSCHEME, Section 2.1) and produces a Token (AUTHSCHEME, Section 2.2), as shown in the figure below. <del> Issuers provide a Private and Public Key, denoted "skI" and "pkI" respectively, used to produce tokens as input to the protocol.  See issuer-configuration for how this key-pair is generated. </del>  Clients provide the following as input to the issuance protocol: 6. This section describes a variant of the issuance protocol in private- <del> flow for producing publicly verifiable tokens.  It differs from the previous variant in that the output tokens are publicly verifiable by anyone with the Issuer Public Key. This means any Origin can select a given Issuer to produce tokens, as long as the Origin has the Issuer public key, without explicit coordination or permission from the Issuer.  This is because the Issuer does not learn the Origin that requested the token during the issuance protocol. </del>  Beyond this difference, the publicly verifiable issuance protocol variant is nearly identical to the privately verifiable issuance value "nonce" using the input challenge and Issuer key identifier as follows: <del> The rsabssa_blind function is defined in BLINDRSA, Section 5.1.1.. The Client stores the nonce and challenge_digest values locally for use when finalizing the issuance protocol to produce a token (as described in public-finalize). </del>  The Client then creates a TokenRequest structured as follows: Client, the Issuer completes the issuance flow by computing a blinded response as follows: <del> This is encoded and transmitted to the client in the following </del>  TokenResponse structure: <del> The rsabssa_blind_sign function is defined in BLINDRSA, Section 5.1.2..  The Issuer generates an HTTP response with status code 200 whose content consists of TokenResponse, with the content type set as "application/private-token-response". </del>  6.3. Upon receipt, the Client handles the response and, if successful, processes the content as follows: <del> The rsabssa_finalize function is defined in BLINDRSA, Section 5.1.3.. If this succeeds, the Client then constructs a Token as described in </del>  AUTHSCHEME as follows: The Token.nonce value is that which was sampled in private-request. <del> If the rsabssa_finalize function fails, the Client aborts the protocol. </del>  6.4.

This link is broken in a few ways. Note that the links has an trailing period in it, which is only part of the problem there; there is no Section 5.1.2 or Section "5.1.2.". Also, the function is called "BlindSign" in that version of the draft.
In the issuance protocol draft, there are a few places where it is assumed that a value will be a certain length, but no effort has been made to explicitly set a length. In : Is the 0x0002 two octets? Sure, you might readily assume that, but nothing says that explicitly. The same assumption appears in Sections 5.1 and 5.5.

defined in ARCHITECTURE. Unless otherwise specified, this document encodes protocol messages  <ins> in TLS notation from Section 3 of TLS13.  Moreover, all constants are </ins> in network byte order. 3. (AUTHSCHEME, Section 2.1) and produces a Token (AUTHSCHEME, Section 2.2), as shown in the figure below.  <ins> This section describes a variant of this issuance protocol for producing privately verifiable tokens using the protocol in OPRF.  In particular, this variant of the issuance protocol uses the OPRF(P-384, SHA-384) ciphersuite. In this variant, Issuers provide a Private and Public Key, denoted "skI" and "pkI" respectively, used to produce tokens as input to the protocol.  See issuer-configuration for how this key-pair is generated. </ins> Clients provide the following as input to the issuance protocol: 6. This section describes a variant of the issuance protocol in private-  <ins> flow for producing publicly verifiable tokens using the protocol in BLINDRSA.  In particular, this variant of the issuance protocol works for the RSABSSA-SHA384-PSS-Deterministic and RSABSSA-SHA384-PSSZERO- Deterministic blind RSA protocol variants described in Section 5 of BLINDRSA. The publicly verifiable issuance protocol differs from the protocol in private-flow in that the output tokens are publicly verifiable by anyone with the Issuer Public Key. This means any Origin can select a given Issuer to produce tokens, as long as the Origin has the Issuer public key, without explicit coordination or permission from the Issuer.  This is because the Issuer does not learn the Origin that requested the token during the issuance protocol. </ins> Beyond this difference, the publicly verifiable issuance protocol variant is nearly identical to the privately verifiable issuance value "nonce" using the input challenge and Issuer key identifier as follows:  <ins> The PrepareIdentity and Blind functions are defined in Section 4.1 of BLINDRSA and Section 4.2 of BLINDRSA, respectively.  The Client stores the nonce and challenge_digest values locally for use when finalizing the issuance protocol to produce a token (as described in public-finalize). </ins> The Client then creates a TokenRequest structured as follows: Client, the Issuer completes the issuance flow by computing a blinded response as follows:  <ins> The BlindSign function is defined in Section 4.3 of BLINDRSA.  The result is encoded and transmitted to the client in the following </ins> TokenResponse structure:  <ins> The Issuer generates an HTTP response with status code 200 whose content consists of TokenResponse, with the content type set as "application/private-token-response". </ins> 6.3. Upon receipt, the Client handles the response and, if successful, processes the content as follows:  <ins> The Finalize function is defined in Section 4.4 of BLINDRSA.  If this succeeds, the Client then constructs a Token as described in </ins> AUTHSCHEME as follows: The Token.nonce value is that which was sampled in private-request.  <ins> If the Finalize function fails, the Client aborts the protocol. </ins> 6.4.


issuance public key based on the blind RSA signature scheme BLINDRSA. This document does not cover the Privacy Pass architecture, including <del> choices that are necessary for ensuring that client privacy leaks. This information is covered in ARCHITECTURE. </del>  2.

This should presumably say "for ensuring that client privacy does not leak" or "to prevent client privacy leaks."

issuance public key based on the blind RSA signature scheme BLINDRSA. This document does not cover the Privacy Pass architecture, including  <ins> choices that are necessary for deployment and application specific choices for protecting client privacy.  This information is covered in ARCHITECTURE. </ins> 2.


5.5. Issuers are configured with Private and Public Key pairs, each <del> denoted "skI" and "pkI", respectively, used to produce tokens.  A RECOMMENDED method for generating key pairs is as follows: </del>  The key identifier for a public key "pkI", denoted "token_key_id", is computed as follows: Issuers are configured with Private and Public Key pairs, each denoted skI and pkI, respectively, used to produce tokens.  Each key <del> pair SHALL be generated as as specified in FIPS 186-4 DSS. </del>  The key identifier for a keypair (skI, pkI), denoted "token_key_id", is computed as SHA256(encoded_key), where encoded_key is a DER-

diverges from . In the earlier section: In the latter, this approximates to: ... with no 0x0002.
I would be fine with adding a token type separator to the type2 variant. It's a simple enough change to make and deploy right now. NAME NAME thoughts?
NAME is there a reason the type 1 key ID needs 0x0001 concatenated to it?
We did this for separation between privacy pass and other potential uses of the same key. I don't remember exactly why we didn't do this for type2.
Had a call, proposing to make things consistent by removing the for Type 1, since it doesn't seem to add any benefit, since the token_input is already binding the protocol to the type and challenge. Also recommending adding more text (in security considerations) to make it very clear that keys ought to not be reused across protocols.

5.5. Issuers are configured with Private and Public Key pairs, each  <ins> denoted "skI" and "pkI", respectively, used to produce tokens.  These keys MUST NOT be reused in other protocols.  A RECOMMENDED method for generating key pairs is as follows: </ins> The key identifier for a public key "pkI", denoted "token_key_id", is computed as follows: Issuers are configured with Private and Public Key pairs, each denoted skI and pkI, respectively, used to produce tokens.  Each key  <ins> pair SHALL be generated as as specified in FIPS 186-4 DSS.  These key pairs MUST NOT be reused in other protocols. </ins> The key identifier for a keypair (skI, pkI), denoted "token_key_id", is computed as SHA256(encoded_key), where encoded_key is a DER-


The Issuer parameters can be obtained from an Issuer via a directory object, which is a JSON object (RFC8259, Section 4) whose values are <del> other JSON values (RFC8259, Section 3) for the parameters. </del>  <del> Each "token-keys" JSON object contains the following fields and corresponding raw values. </del>  Issuers MAY advertise multiple token-keys for the same token-type to support key rotation.  In this case, Issuers indicate preference for Altogether, the Issuer's directory could look like: <del> Issuer directory resources have the media type "application/json" and are located at the well-known location /.well-known/token-issuer- directory; see wkuri-reg for the registration information for this well-known URI. </del>  4. 8.  8.1. This document updates the "Well-Known URIs" Registry WellKnownURIs This specification defines the following protocol messages, along with their corresponding media types:  TokenRequest: "application/private-token-request" TokenResponse: "application/private-token-response" application <del> private-token-request </del>  N/A application  private-token-response N/A

The caption for is: "'xxx' Well-Known URI", which is probably wrong.
This is a bit of a hard one to decide for me, but I think that you want to define a media type for the JSON directory. I know that in most cases the content will be served from a .well-known location, but that isn't always.
What would be the benefit of a media type here if the content will always be JSON? That is, I don't see how a media type would influence consumers of the resource.
So that you can make it clear that it is this specific JSON, as opposed to some other JSON.
The table appears without the text referring to it, even with an "as follows". It might be better to reference it directly.

The Issuer parameters can be obtained from an Issuer via a directory object, which is a JSON object (RFC8259, Section 4) whose values are  <ins> other JSON values (RFC8259, Section 3) for the parameters.  The contents of this JSON object are defined in directory-values. </ins>  <ins> Each "token-keys" JSON object contains the fields and corresponding raw values defined in tokenkeys-values. </ins> Issuers MAY advertise multiple token-keys for the same token-type to support key rotation.  In this case, Issuers indicate preference for Altogether, the Issuer's directory could look like:  <ins> Issuer directory resources have the media type "application/token- issuer-directory" and are located at the well-known location /.well- known/token-issuer-directory; see wkuri-reg for the registration information for this well-known URI. </ins> 4. 8. <ins> This section contains considerations for IANA. </ins> 8.1. This document updates the "Well-Known URIs" Registry WellKnownURIs This specification defines the following protocol messages, along with their corresponding media types: <ins> Token issuer directory: "application/token-issuer-directory" </ins> TokenRequest: "application/private-token-request" TokenResponse: "application/private-token-response" application  <ins> token-issuer-directory </ins> N/A application <ins> private-token-request N/A None "binary" see N/A this specification N/A N/A see Authors' Addresses section COMMON N/A see Authors' Addresses section IESG 8.3.3. application </ins> private-token-response N/A


DeriveKeyPair. The constants "Ne" and "Ns" are as defined in OPRF, Section 4 for <del> OPRF(P-384, SHA-384). </del>  5.1. this might be provided by the redemption protocol in AUTHSCHEME. Given this configuration and these inputs, the two messages exchanged <del> in this protocol are described below. </del>  6.1.

doesn't define . The preceding text to the example says that Nk is 512, but AFAICT the value of Nk is not relevant to the example.
Section 8.2 defines Nk=256 for type 0x0002. Section 6.1 should still apply for any value Nk if another type is added for a different size key. My two suggestions would be: (1) mention in Section 6.1 that Nk is fixed according to the token type definition and (2) use Nk=256 for the example so it matches the only currently defined blind token type (0x0002).

DeriveKeyPair. The constants "Ne" and "Ns" are as defined in OPRF, Section 4 for  <ins> OPRF(P-384, SHA-384).  The constant "Nk" is defined by private-token- type. </ins> 5.1. this might be provided by the redemption protocol in AUTHSCHEME. Given this configuration and these inputs, the two messages exchanged  <ins> in this protocol are described below.  The constant "Nk" is defined by public-token-type. </ins> 6.1.


Issuers MUST provide two parameters for configuration: <del> Issuer Request URI: A token request URL for generating access </del>  tokens.  For example, an Issuer URL might be <del> https://issuer.example.net/request.  This parameter uses resource media type "text/plain". </del>  Issuer Public Key values: A list of Issuer Public Keys for the issuance protocol.

Are the changes to other files on this one intentional NAME ?
Oh, hrm, no, they're not. I'll remove them.
NAME fixed!
There are several related issues in URL Should the well-known location require mTLS? The two well-known public implementations previously highlighted by Apple disagree on this point. Our opinion: mTLS should not be required for the token issuer directory. is underspecified. Should this be an absolute URI, a relative URI, or allow either format? Our opinion: We prefer relative URIs, and think either option should be supported. A relative URI is also used by at least one well-known public implementation.
No. That's deployment specific decision. Either is fine, as evidenced by current implementations. We'll make this clear.
Since this URI is intended to be used as a URL later in the protocol -- and the description in fact calls it a URL -- would it be cleaner to name the parameter "Issuer Request URL"/? What "thing" is actually ? The directory itself is , the resulting content is JSON (whose strings do not carry a notion of media types), and the token request/response using this URI use /.
I think just dropping the media type mention at all is probably best here. It's just a URL string, so let's just call it that. Does work for you?
That looks much better. Should the parameter also be ?

Issuers MUST provide two parameters for configuration:  <ins> Issuer Request URL: A token request URL for generating access </ins> tokens.  For example, an Issuer URL might be  <ins> https://issuer.example.net/request. </ins> Issuer Public Key values: A list of Issuer Public Keys for the issuance protocol.


known/token-issuer-directory; see wkuri-reg for the registration information for this well-known URI.  5. The privately verifiable issuance protocol allows Clients to produce

Most likely, clients and origins will be caching issuer directories. Is it worth offering any guidance to client/origin implementations regarding caching? Is honoring cache-control response headers sufficient? And if so, should that be called out explicitly as a reminder to implementers (who might be building a custom cache or perhaps caching the parsed JSON content separately from an existing HTTP layer)? Is it worth offering any guidance to issuers about how long they should assume directory changes will take to reach ~100% of clients and issuers? (My gut says no to this one -- but I am throwing it out in case others think it is worthwhile.)
Using cache control directives for this key material seems fine, provided it's done in accordance with your key rotation schedule.
The proposed change addresses the primary concern of this issue. Typo? Should it be "results in"?
Yep, fixed.
I believe there is a race condition if an issuer tries to add or remove s in its directory. When adding a token type, a client may see the a key for the new in the directory and use it even though the origin may have a slightly stale directory. When removing a token, a client may see still see the key for the old in a slightly stale directory and use it even the the origin may already have refreshed its directory. One potential way to address this would be to extend or replace key ordering with a designation of which key(s) are "active." The client would only pick "active" keys to make requests to an issuer, but origins would verify against all listed keys. A could then be "rotated" in/out of use by having it appear for some time as inactive before activating it or removing it entirely.
Hmm, unless there's some sort of additional consistency mechanism in place, clients are not really expected to fetch or inspect the issuer's configuration. This is only useful information for the origin. This relates to how the information is cached, so I think we can address this and at the same time.
There is still some potential for skew even with cache-control. The update includes a new to refetch the config if there is evidence that it's stale, and that certainly could help in many cases. Presumably an issuer must still support a key for some amount of time after removing it from the directory for at least the cache max-age. (Is that worth mentioning explicitly?) A client that is using consistency may fail to validate a token key if it has a fresher directory than the origin and the tokentype has been removed. One option would be for consistency providers to keep old keys around for some time after they are removed from the directory. Another option would be for the client to try other tokentypes that were offered by the origin. Would it be helpful to mention somewhere (issuance protocol or maybe the http auth scheme?) that clients should try a different (supported) token_type if the first attempt fails?
There will always be potential for skew in a distributed system like this. We already note that the issuer can advertise multiple keys (sorted by order of preference) to address this particular problem: I don't think we need to say anything more without just being confusing.

known/token-issuer-directory; see wkuri-reg for the registration information for this well-known URI. <ins> Issuers SHOULD use HTTP caching to permit caching of this resource RFC5861.  The cache lifetime depends on the Issuer's key rotation schedule.  Regular rotation of token keys is recommended to minimize the risk of key compromise. Issuers can control cache lifetime with the Cache-Control header, as follows: Consumers of the Issuer directory resource SHOULD follow the usual HTTP caching RFC9111 semantics when processing this resource.  Long cache lifetimes may result in use of stale Issuer configuration information, whereas short lifetimes may result in decreased performance.  When use of an Issuer configuration results in token issuance failures, e.g., because the configuration information is too stale, the directory SHOULD be fetched and revalidated. </ins> 5. The privately verifiable issuance protocol allows Clients to produce


"application/private-token-request".  An example request is shown below.  Upon receipt of the request, the Issuer validates the following conditions: The TokenRequest.blinded_msg is of the correct size. If any of these conditions is not met, the Issuer MUST return an HTTP <del> 400 error to the client. 5.2. Upon receipt of a TokenRequest, the Issuer tries to deseralize </del>  TokenRequest.blinded_msg using DeserializeElement from Section 2.1 of OPRF, yielding "blinded_element".  If this fails, the Issuer MUST return an HTTP 400 error to the client.  Otherwise, if the Issuer is request is "application/private-token-request".  An example request is shown below:  Upon receipt of the request, the Issuer validates the following conditions: If any of these conditions is not met, the Issuer MUST return an HTTP 400 error to the Client, which will forward the error to the client. <del> 6.2. If the Issuer is willing to produce a token token to the Client, the Issuer completes the issuance flow by computing a blinded response as follows: </del>  This is encoded and transmitted to the client in the following TokenResponse structure:

ends with two paragraphs that really belong in Section 5.2, because they are about the processing of the request.

"application/private-token-request".  An example request is shown below. <ins> 5.2. </ins> Upon receipt of the request, the Issuer validates the following conditions: The TokenRequest.blinded_msg is of the correct size. If any of these conditions is not met, the Issuer MUST return an HTTP  <ins> 400 error to the client.  The Issuer then tries to deseralize </ins> TokenRequest.blinded_msg using DeserializeElement from Section 2.1 of OPRF, yielding "blinded_element".  If this fails, the Issuer MUST return an HTTP 400 error to the client.  Otherwise, if the Issuer is request is "application/private-token-request".  An example request is shown below: <ins> 6.2. </ins> Upon receipt of the request, the Issuer validates the following conditions: If any of these conditions is not met, the Issuer MUST return an HTTP 400 error to the Client, which will forward the error to the client.  <ins> Otherwise, if the Issuer is willing to produce a token token to the Client, the Issuer completes the issuance flow by computing a blinded response as follows: </ins> This is encoded and transmitted to the client in the following TokenResponse structure: