RFC 9577
The Privacy Pass HTTP Authentication Scheme
RFC 9577: The Privacy Pass HTTP Authentication Scheme ๐
Okay bestie, this is the spec for Privacy Pass over HTTP, and it's giving privacy and authorization with zero drama ๐ฆ
- Stream: Internet Engineering Task Force (IETF) ๐ธ
- RFC: 9577
- Authors: T. Pauly (Apple Inc.), S. Valdez (Google LLC), C. A. Wood (Cloudflare) ๐
- Category: Standards Track โจ
- ISSN: 2070-1721
- Date: June 2024
- Obsoletes / Updates: neither is listed in this title block ๐ง
Abstract
So this doc defines an HTTP authentication scheme for Privacy Pass ๐ It's a privacy-preserving authentication mechanism used for authorization, and it's lowkey iconic. Clients can use the scheme to redeem Privacy Pass tokens with an Origin. Origins can also use it to challenge Clients to present Privacy Pass tokens ๐
Status of This Memo
This one is an Internet Standards Track document ๐ฅ
It's a product of the Internet Engineering Task Force (IETF), so it represents the consensus of the IETF community. It went through public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check Section 2 of RFC 7841 ๐ซถ
For the current status, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc9577 โจ
Copyright Notice
Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stood on the publication date. Please actually read these, bestie, because they explain your rights and restrictions for this document ๐ Code Components pulled out of this document must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions. They come without warranty, as the Revised BSD License describes ๐
Table of Contents
1. Introduction
1.1. Terminology
2. HTTP Authentication Scheme
2.1. Token Challenge
2.1.1. Token Challenge Structure
2.1.2. Sending Token Challenges
2.1.3. Processing Token Challenges
2.1.4. Token Caching
2.2. Token Redemption
2.2.1. Token Structure
2.2.2. Sending Tokens
2.2.3. Token Verification
3. Client Behavior
3.1. Choosing to Redeem Tokens
3.2. Choosing between Multiple Challenges
4. Origin Behavior
4.1. Greasing
5. Security Considerations
5.1. Randomness Requirements
5.2. Replay Attacks
5.3. Reflection Attacks
5.4. Token Exhaustion Attacks
5.5. Timing Correlation Attacks
5.6. Cross-Context Linkability Attacks
6. IANA Considerations
6.1. Authentication Scheme
6.2. Privacy Pass Token Types Registry
6.2.1. Reserved Values
7. References
7.1. Normative References
7.2. Informative References
Appendix A. Test Vectors
A.1. Challenge and Redemption Structure Test Vectors
A.2. HTTP Header Test Vectors
Authors' Addresses
1. Introduction โจ
Privacy Pass tokens are unlinkable authenticators, which means they can anonymously authorize a Client (see [ARCHITECTURE]) ๐ฆ Token Issuers generate them based on authentication, attestation, or some earlier action, like solving a CAPTCHA ๐งฉ A Client holding one of these tokens can prove that it got a token issued. The relying party that redeems the token (the Origin) still can't link it back to the issuance flow, so it's private af ๐
Different types of authenticators can be used as Privacy Pass tokens, and they can use different token issuance protocols ๐
This document defines a common HTTP authentication scheme ([HTTP], Section 11), called "PrivateToken". It lets Clients redeem several kinds of Privacy Pass tokens ๐
Clients and relying parties (Origins) use this scheme to run the token challenge and token redemption flow ๐ซถ Origins challenge Clients for a token with an HTTP authentication challenge, sent in the WWW-Authenticate response header field ๐ Then Clients react by sending a new request with a matching token, using the Authorization request header field โจ Clients make tokens that match the Origin's token challenge by running one of the token issuance protocols defined in [ISSUANCE]. Presenting a token in an Authorization request header field is called "token redemption" ๐ Here's how the Client and Origin interact:
+--------+ +--------+
| Origin | | Client |
+---+----+ +---+----+
| |
+-- WWW-Authenticate: TokenChallenge -->|
| |
| (Run issuance protocol)
| |
|<------ Authorization: token ----------+
| |
Figure 1: Challenge and Redemption Protocol Flow ๐ธ
On top of supporting different token issuance protocols, this scheme can optionally use tokens tied to Origin-chosen contexts and specific Origin names ๐ง Relying parties that request and redeem tokens can pick the kind of token that fits their use case ๐ These options (1) let different deployment models prevent double-spending and (2) let both interactive (online challenges) and non-interactive (pre-fetched) tokens exist ๐
1.1. Terminology
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in BCP 14 [RFC2119] [RFC8174], but only when they appear in all capitals, just like here ๐
Unless stated otherwise, this document writes protocol messages in TLS notation from [TLS13], Section 3 ๐งพ
This doc uses the terms "Client", "Origin", "Issuer", "issuance protocol", and "Token" as [ARCHITECTURE] defines them. It also uses these terms in more specific ways ๐
- Issuer key: Keying material that goes with an issuance protocol to create a signed token ๐
- Token challenge: A request for tokens, sent from an Origin to a Client in the WWW-Authenticate HTTP header field ๐จ It identifies one specific token Issuer and issuance protocol. Token challenges can optionally include a redemption context (see Section 2.1.1.2), a list of associated Origins, or both. Those optional values can then get bound to the token that's issued ๐
- Token redemption: When a Client presents a token to an Origin in an HTTP request, using the Authorization HTTP header field ๐ซถ
2. HTTP Authentication Scheme ๐ฆ
Token redemption happens through HTTP authentication ([HTTP], Section 11), using the scheme "PrivateToken". Origins challenge Clients to present a token from a specific Issuer (Section 2.1) ๐ Once a Client has gotten a token from that Issuer, or already has a valid one, it presents the token to the Origin (Section 2.2) โจ Presenting a token as authentication to an Origin is also called "spending" a token ๐ธ
To stop linkability across different transactions, Clients will often present a particular "PrivateToken" only once ๐ Origins can still link several transactions to the same Client if that Client spends the same token value more than once. So Origins ought to expect at most one unique token value, carried in one request, for each challenge ๐ง
The rest of this section goes deeper into the token challenge and redemption interactions ๐ธ
2.1. Token Challenge
Origins send a token challenge to Clients in a WWW-Authenticate header field with the "PrivateToken" scheme ๐จ This authentication scheme has two mandatory parameters: one holds a token challenge, and the other holds the token-key used to produce (and verify) a matching token ๐
Origins that support the "PrivateToken" authentication scheme need to handle these tasks when building the WWW-Authenticate header field:
- Pick which Issuer to use, and set up the Issuer name and token-key to include in WWW-Authenticate token challenges. The Issuer name goes in the token challenge, and the Issuer token-key fills the WWW-Authenticate header parameter ๐ง
- Decide on a redemption context construction to include in the token challenge, as discussed in Section 2.1.1.2 ๐
- Choose the Origin information to include in the token challenge ๐ This can be empty, which allows fully cross-Origin tokens. It can be a single Origin name that matches the Origin itself, for per-Origin tokens. Or it can be a list of Origin names that includes the Origin itself. For more on how cross-Origin and per-Origin tokens differ, see Section 3.4 of [ARCHITECTURE] ๐
Once those decisions are made, Origins build the WWW-Authenticate header by first constructing the token challenge as described in Section 2.1.1 ๐ Origins send challenges as described in Section 2.1.2, and Clients process them as described in Sections 2.1.3 and 2.1.4 ๐ซถ
2.1.1. Token Challenge Structure โจ
okay so this is the default challenge structure, and it works across token types ๐ but heads up, future token types MAY extend or modify the structure of the challenge ๐ฆ the registry in Section 6.2 is where the relationship between token_type and the TokenChallenge message gets established and defined, so go check there bestie ๐
every token challenge MUST begin with a 2-octet integer that defines the token type, in network byte order ๐ฅ this type tells you which issuance protocol made the token, and it decides the structure and semantics of everything after it ๐ values live in an IANA registry (see Section 6.2) ๐ธ and clients MUST ignore challenges with token types they do not support ๐
even when a token type uses the default structure, the rules for which fields are present or how they get read can differ between token types ๐ for example, some token types might require that origin_info is non-empty, while others allow it to be empty ๐ง
the default TokenChallenge message looks like this:
struct {
uint16_t token_type;
opaque issuer_name<1..2^16-1>;
opaque redemption_context<0..32>;
opaque origin_info<0..2^16-1>;
} TokenChallenge;
here's what each field means ๐
- token_type is a 2-octet integer, in network byte order, as described above. ๐
- issuer_name is an ASCII string that identifies the Issuer, using the format of a server name as defined in Section 2.1.1.1. This name identifies the Issuer that is allowed to issue tokens that can be redeemed by this Origin. The field that stores this string in the challenge is prefixed with a 2-octet integer indicating the length, in network byte order. ๐ฆ
- redemption_context is a field that is either 0 or 32 bytes, prefixed with a single octet indicating the length (either 0 or 32). If the value is non-empty, it is a 32-byte value generated by the Origin that lets the Origin require that Clients fetch tokens bound to a specific context, instead of reusing tokens that were fetched for other contexts. See Section 2.1.1.2 for example contexts that might be useful in practice. Challenges with redemption_context values of invalid lengths MUST be ignored. ๐
- origin_info is an ASCII string that is either empty or contains one or more Origin names that let a token be scoped to a specific set of Origins. Each Origin name uses the format of a server name as defined in Section 2.1.1.1. The string is prefixed with a 2-octet integer indicating 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 whitespace. If this field is not empty, the Origin MUST include its own name as one of the names in the list. โญ
if origin_info has multiple Origin names, the challenge is valid for any of the Origins in the list ๐ซถ that includes the Origin that issued the challenge, which must always be in the list if it isn't empty (see Section 2.1.3) ๐ this is super useful when Clients pre-fetch and cache tokens for a particular challenge (origin_info included) and then later redeem those tokens with one of the Origins in the list ๐ญ more on token caching in Section 2.1.4 ๐
2.1.1.1. Server Name Encoding ๐ธ
server names in a token challenge are ASCII strings with a hostname and an optional port, where the port is assumed to be "443" if it's missing ๐ the names use the format of the authority portion of a URI, as defined in Section 3.2 of [URI] ๐ง the names MUST NOT include a "userinfo" portion of an authority ๐ so "issuer.example.com" or "issuer.example.com:8443" are valid, but "issuer@example.com" is not ๐
2.1.1.2. Redemption Context Construction ๐ฎ
the TokenChallenge redemption context lets the Origin figure out the context a given token can be redeemed in ๐ฆ it can be a unique per-request nonce built from 32 freshly generated random bytes โจ it can also represent state or properties of the Client session ๐ some example properties and methods for building the context are below, and this list is not exhaustive ๐ซถ
Context bound to a given time window: Construct the redemption context as F(current time window), where F is a pseudorandom function. โฐ
Context bound to a Client network based on Autonomous System Number (ASN): Construct the redemption context as F(Client ASN), where F is a pseudorandom function. ๐
Context bound to a given time window and Client network: Construct the redemption context as F(current time window, Client ASN), where F is a pseudorandom function. ๐
preventing double-spending on tokens means the Origin has to keep state tied to the redemption context ๐ค an empty redemption context isn't bound to any property of the Client request, so double-spend state has to be stored and shared across all Origin servers that can accept tokens until token-key expiration or rotation ๐ for a non-empty redemption context, the double-spend state only needs to be stored across the set of Origin servers that will accept tokens with that redemption context ๐
Origins that share redemption contexts (same redemption context, same Issuer, and same origin_info field in the TokenChallenge) MUST share the state needed to enforce double-spend prevention ๐ฅ Origins should think about how complicated that shared state is to run before they choose to share redemption contexts ๐ง if they fail to sync this state and use it for double-spend prevention, Clients might be able to redeem tokens at one Origin that were issued after an interaction with another Origin that shares the context ๐ฑ
2.1.2. Sending Token Challenges ๐
when used in an authentication challenge, the "PrivateToken" scheme uses these parameters ๐
- challenge, which contains a base64url TokenChallenge value, encoded per [RFC4648]. This document follows the default padding behavior described in Section 3.2 of [RFC4648], so the base64url value MUST include padding. As an authentication parameter (auth-param from [HTTP], 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 parameter is required for all challenges. ๐
- token-key, which contains a base64url encoding of the public key for use with the issuance protocol indicated by the challenge. See [ISSUANCE] for more information about how this public key is used by the issuance protocols described in that specification. The encoding of the public key is determined by the token type; see Section 6.2. As with challenge, the base64url value MUST include padding. As an authentication parameter (auth-param from [HTTP], 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 parameter MAY be omitted in deployments where Clients can retrieve the Issuer key using an out-of-band mechanism. ๐ฆ
- max-age, which is an optional parameter made up of the number of seconds for which the challenge will be accepted by the Origin. โณ
the header field MAY also include the standard realm parameter if you want ๐ธ issuance protocols MAY define other parameters, some of which might be required ๐ง clients MUST ignore parameters in challenges that aren't defined for the issuance protocol that goes with the token type in the challenge ๐
for example, the WWW-Authenticate header field could look like this:
WWW-Authenticate:
PrivateToken challenge="abc...", token-key="123..."
2.1.2.1. Sending Multiple Token Challenges ๐
it's possible for the WWW-Authenticate header field to include multiple challenges ([HTTP], Section 11.6.1) ๐ this lets the Origin show support for different token types or different Issuers, or include multiple redemption contexts โจ for example, the WWW-Authenticate header field could look like this:
WWW-Authenticate:
PrivateToken challenge="abc...", token-key="123...",
PrivateToken challenge="def...", token-key="234..."
Origins should only include challenges for different types of issuance protocols with functionally equivalent properties ๐ for instance, both issuance protocols in [ISSUANCE] have the same functional properties, just with different mechanisms for verifying the resulting tokens during redemption ๐ฅ since Clients are free to pick whichever challenge they want to use when they have options, mixing multiple challenges with different functional properties for one use case is nonsensical ๐ญ if the Origin prefers one challenge over another (say, one uses a token type that's faster to verify), it can sort it to be first in the list as a hint for the Client ๐ซถ
2.1.3. Processing Token Challenges ๐
when a Client gets a challenge, it validates the TokenChallenge structure before taking any action, like fetching a new token or redeeming one in a new request ๐ the validation requirements are:
- The token_type is recognized and supported by the Client; ๐
- The TokenChallenge structure is well-formed; and ๐ฆ
- If the origin_info field is non-empty, the name of the Origin that issued the authentication challenge is included in the list of Origin names. Comparison of the Origin name that issued the authentication challenge against elements in the origin_info list is done via case-insensitive equality checks. ๐ธ
if validation fails, the Client MUST NOT fetch or redeem a token based on the challenge ๐ซ clients MAY have further restrictions and requirements around validating when a challenge is acceptable or valid ๐ for example, Clients can choose to ignore challenges that list Origin names the current connection isn't authoritative for (according to the TLS certificate) ๐
caching and pre-fetching of tokens are discussed in Section 2.1.4 ๐
2.1.4. Token Caching โจ
okay so clients can make a whole batch of tokens from one TokenChallenge and stash them for later ๐งบ this is lowkey genius bc it splits up when a token gets issued from when it gets redeemed ๐ซถ that's better for privacy, and it means clients don't have to keep waiting around to receive new tokens through the issuance protocol ๐
cached tokens can only be redeemed if they match all of the fields in the TokenChallenge: token_type, issuer_name, redemption_context, and origin_info ๐ so clients ought to store cached tokens keyed on all of these fields, so they don't waste time trying to redeem a token that doesn't match ๐ also, every token has its own unique Client nonce, and that nonce gets sent during token redemption (Section 2.2) ๐ฅ
โ ๏ธ if a Client grabs a batch of tokens that are bound to a specific redemption context (so the redemption_context in the TokenChallenge wasn't empty), Clients SHOULD throw those tokens out when they flush state like HTTP cookies [COOKIES] ๐ same goes if there's a network change and the Client doesn't have any Origin-specific state like HTTP cookies. bc using these tokens somewhere that otherwise wouldn't be linkable to the original context could let the Origin recognize the Client ๐ญ
2.2. Token Redemption ๐ฆ
the output of the issuance protocol is a token that matches the Origin's challenge (see Section 2.1) ๐
2.2.1. Token Structure ๐ธ
okay this part is the main character ๐ a token is a structure that starts with a 2-octet field for the token type, and it MUST match the token_type in the TokenChallenge structure โจ that value decides the structure and semantics of the rest of the token ๐ง
this document defines the default token structure that can be used across token types, but future token types MAY extend or modify the structure of the token. see Section 6.2 for the registry info that sets up and defines the relationship between token_type and the contents of the token structure ๐
the default token message looks like this:
struct {
uint16_t token_type;
uint8_t nonce[32];
uint8_t challenge_digest[32];
uint8_t token_key_id[Nid];
uint8_t authenticator[Nk];
} Token;
here's what each field means ๐
- token_type is a 2-octet integer, in network byte order, as described above.
- nonce is a 32-octet value holding a Client-generated random nonce ๐ฒ
- challenge_digest is a 32-octet value holding the hash of the original TokenChallenge, SHA-256(TokenChallenge), where SHA-256 is as defined in [SHS]. changing the hash function to something other than SHA-256 would need a new token type and token structure (bc the contents of challenge_digest would be computed differently), and that can happen in a future specification ๐ฎ
- token_key_id is a Nid-octet identifier for the token authentication key. its value is defined by the token_type and the corresponding issuance protocol ๐
- authenticator is a Nk-octet authenticator that is cryptographically bound to the preceding fields in the token. see Section 2.2.3 for how this field gets used when verifying a token ๐ the token_type and corresponding issuance protocol decide the value of the authenticator field and how it gets computed. the value of the constant Nk depends on token_type, as defined in Section 6.2 ๐ซ
the authenticator value in the token structure is computed over the token_type, nonce, challenge_digest, and token_key_id fields. a token is considered valid if token verification succeeds; see Section 2.2.3 for details on verifying the token and its authenticator value ๐ซง
2.2.2. Sending Tokens ๐
when it's used for Client authorization, the "PrivateToken" authentication scheme defines one parameter, token, which holds the base64url-encoded token structure. just like the challenge parameters (Section 2.1), the base64url value MUST include padding ๐ง as an authentication parameter (auth-param from [HTTP], Section 11.2), the value can be either a token or a quoted-string, and it might need to be a quoted-string if the base64url string includes "=" characters ๐ all unknown or unsupported parameters to "PrivateToken" authentication credentials MUST be ignored ๐
clients present this token structure to Origins in a new HTTP request using the Authorization header field, like this:
Authorization: PrivateToken token="abc..."
for context-bound tokens, Origins store or rebuild the contexts of previous TokenChallenge structures so they can validate the token. a TokenChallenge can be bound to a specific TLS session with a Client, but Origins can also accept tokens for valid challenges in new sessions ๐ Origins SHOULD implement some form of double-spend prevention that stops a token with the same nonce from being redeemed twice. double-spend prevention makes sure Clients can't replay tokens for previous challenges ๐ซ see Section 5.2 for more on replay attacks ๐ for context-bound tokens, this double-spend prevention can require no state or minimal state, since the context can be used to check token uniqueness ๐ง
2.2.3. Token Verification ๐
a token is made of some input that's cryptographically bound to an authenticator value, like a digital signature. verifying a token means checking that the authenticator value is correct โ
the authenticator value is what you get when you run and finalize the issuance protocol for the token type, using these values as the input:
struct {
uint16_t token_type;
uint8_t nonce[32];
uint8_t challenge_digest[32];
uint8_t token_key_id[Nid];
} AuthenticatorInput;
the values of these fields are the same as described in Section 2.2.1 ๐ซถ the actual cryptographic check depends on the token type; see Sections 5.4 and 6.4 of [ISSUANCE] for the verification instructions for the issuance protocols described in that spec ๐ so the security properties of the token (like how likely it is that someone could forge an authenticator value without running the issuance protocol) depend on the cryptographic algorithm the issuance protocol uses, as set by the token type ๐๐ค
3. Client Behavior ๐งโโ๏ธ
when a Client gets one or more token challenges in response to a request, it has a few choices to make ๐
- whether or not to redeem a token via a new request to the Origin.
- whether to redeem a previously issued and cached token, or redeem a token freshly issued from the issuance protocol.
- if multiple challenges were sent, which challenge to use for redeeming a token on a subsequent request.
the approach to these choices depends on the application's use case, plus the deployment model (see Section 4 of [ARCHITECTURE] for discussion of the different deployment models) ๐ท
3.1. Choosing to Redeem Tokens ๐ฆ
some applications of tokens might require Clients to always present a token as authentication in order to successfully make requests ๐ for example, a restricted service that only wants to allow access to valid users, but wants to do it without learning specific user credential information, could use tokens based on attesting user credentials ๐ต๏ธ in these kinds of use cases, Clients will need to always redeem a token to successfully make a request ๐
lots of other Privacy Pass use cases involve open services that must work with any Client, including ones that either cannot redeem tokens or can only sometimes redeem them ๐ for example, a service can use tokens to reduce how often CAPTCHAs get shown to users ๐ in cases like this, services will regularly run into Clients that can't redeem a token or choose not to. to avoid these services relying on always getting tokens, Clients that can redeem tokens can ignore token challenges with some non-trivial probability (and instead act like a Client that either doesn't support redeeming tokens or can't generate a new token, by not sending a new request that contains a token to redeem) ๐ฒ see Section 5.1 of [ARCHITECTURE] for further considerations about avoiding discriminatory behavior across Clients when using Privacy Pass tokens โ๏ธ
Clients might also choose not to redeem tokens in later requests when the token challenges show erroneous or malicious behavior from the challenging Origin ๐ฉ for example, if a Client's ability to generate tokens via an Attester and Issuer is limited to a certain rate, a malicious Origin could send a flood of token challenges with unique redemption contexts in order to (1) make the Client run out of its ability to generate new tokens or (2) overwhelm issuance servers ๐ฑ the limits here vary depending on the deployment, but Clients SHOULD have some implementation-specific policy to minimize the number of tokens that can be retrieved by Origins ๐ก๏ธ
3.2. Choosing between Multiple Challenges ๐ญ
a single response from an Origin can include multiple token challenges ๐ for example, a set of challenges could include different token types and Issuers, so Clients can pick a preferred Issuer or type ๐โโ๏ธ
if Clients choose to respond, they SHOULD satisfy exactly one of the challenges presented. hmm wait, let me fix that: the original text says Clients "should" satisfy exactly one, so it's lowercase here ๐ the choice of which challenge to use for redeeming tokens is up to Client policy. this can involve which token types are supported or preferred, which Issuers are supported or preferred, or whether the Client can use cached tokens based on the redemption context or Origin information in the challenge. see Section 2.1.4 for more discussion on token caching ๐พ regardless of how the choice is made, it SHOULD be done in a consistent manner so the choice doesn't reveal information about the specific Client; see Section 6.2 of [ARCHITECTURE] for more details on the privacy implications of issuance consistency ๐
4. Origin Behavior ๐
Origins choose what token challenges to send to Clients, and these will vary depending on the use case and deployment model ๐ซ the Origin chooses which token types, Issuers, redemption contexts, and Origin information to include in challenges. if an Origin sends multiple challenges, each challenge SHOULD be equivalent in terms of acceptability for token redemption, since Clients are free to choose to generate tokens based on any of the challenges ๐ธ
Origins ought to think about the time involved in token issuance ๐ฐ๏ธ in particular, a challenge that includes a unique redemption context will stop a Client from using cached tokens, and so can add more delay before the Client is able to redeem a token ๐ข
Origins SHOULD minimize the number of challenges sent to a particular Client context (referred to as the "redemption context" in Section 3.3 of [ARCHITECTURE]), so they don't overwhelm Clients and Issuers with token requests that might make Clients hit rate limits ๐ฆ
4.1. Greasing ๐
Okay so greasing is basically how we keep Clients from getting caught off guard when brand-new token challenges show up ๐ฆ. Origins SHOULD sprinkle in random token types from the reserved "greased" list (the one in Section 6.2) with some non-trivial probability ๐ .
And for setups where tokens aren't actually required (like using them to dodge CAPTCHAs ๐), Origins SHOULD randomly skip challenging Clients for tokens with some non-trivial probability. Why? It keeps the no-token path for Clients that can't redeem tokens getting tested and working consistently ๐งโจ.
5. Security Considerations ๐
This section covers the security considerations for the PrivateToken authentication scheme described in this document ๐ซถ.
5.1. Randomness Requirements
Every random value in the challenge and token MUST be generated with a cryptographically secure source of randomness [RFC4086]. No shortcuts, bestie ๐ญ
5.2. Replay Attacks
Applications SHOULD limit tokens to a single Origin unless their use case can handle replay attacks ๐. Replaying tokens isn't automatically a security or privacy disaster, ngl ๐.
For example, it's totally reasonable for Clients to replay tokens when redeeming them doesn't cause side effects and the Client's requests are already linkable anyway. One setting where this fits is when tokens get sent as part of 0-RTT data ๐ธ.
If redeeming a token actually produces side effects, Origins SHOULD implement an anti-replay mechanism to limit the harm from replays ๐ก๏ธ. Check out [TLS13], Section 8 and [RFC9001], Section 9.2 for the details on anti-replay mechanisms, plus [RFC8470], Section 3 for the safety talk around 0-RTT HTTP data ๐.
5.3. Reflection Attacks
The security properties of token challenges are kind of a mixed bag ๐ญ. It depends on whether the challenge has a redemption context, and on whether it's a per-Origin challenge or not. For instance, cross-Origin tokens with empty contexts can get reflected from one party to another by an attacker, like this ๐:
+--------+ +----------+ +--------+
| Origin | | Attacker | | Client |
+---+----+ +----+-----+ +---+----+
| | |
+--- TokenChallenge -->| |
| +-- (reflect challenge) -->|
| |<-------- Token ----------+
|<-- (reflect token) --+ |
| | |
Figure 2: Reflection Attack Example
5.4. Token Exhaustion Attacks
Okay, this one's a vibe ๐ค. If a Client is holding cross-Origin tokens with empty contexts, any Origin in that cross-Origin set could drain the Client's whole token stash ๐. To stop that, tokens can be scoped to single Origins (with a non-empty origin_info) so they can only be redeemed for one Origin ๐ฏ. Or, if tokens are cross-Origin, Clients can use other tricks to stop a bunch of them getting redeemed at once. For example, if the Origin asks for way more tokens than needed, the Client could just hold off on presenting any tokens for verification if a redemption already happened in a given time window โณ.
Token challenges with a non-empty origin_info bind tokens to one or more specific Origins ๐. As Section 2.1.3 explains, Clients only accept those challenges from the Origin names listed in a non-empty origin_info string. Even when several Origins are listed, a token can only be redeemed for an Origin if the challenge has a match in origin_info. Let's say a.example.com issues a challenge with an origin_info string of a.example.com,b.example.com. A Client can redeem a token fetched for that challenge if and only if b.example.com also has an origin_info string of a.example.com,b.example.com. But if b.example.com had b.example.com, b.example.com,a.example.com, or a.example.com,b.example.com,c.example.com, the strings wouldn't match, and the Client would need to use a different token ๐
โโ๏ธ.
5.5. Timing Correlation Attacks
Context-bound token challenges make Clients obtain matching tokens when they're challenged, instead of presenting one they grabbed from some other context in the past ๐ฐ๏ธ. That can make issuance and redemption happen at roughly the same time, which is kinda risky ๐ฌ. Say a Client gets challenged for a token with a unique context at time T1, then grabs a token at time T2. A colluding Issuer and Origin can link those two events to the same Client if T2 is unique to that Client. This gets harder to pull off as the number of issuance events at time T2 goes up ๐.
Depending on the max-age token challenge parameter, Clients MAY try adding a delay between being challenged and redeeming a token, which makes this kind of linking harder ๐ข๐. For more on correlation risks between token issuance and redemption, see Section 6.3 of [ARCHITECTURE] ๐.
5.6. Cross-Context Linkability Attacks
As we covered in Section 2.1, Clients SHOULD throw away any context-bound tokens when they flush cookies or switch networks ๐งน. The reason is simple: otherwise an Origin could use the redemption context state as a cookie to recognize Clients, and nobody wants that ๐ โโ๏ธ๐ช.
6. IANA Considerations ๐
6.1. Authentication Scheme
IANA registered the PrivateToken authentication scheme in the "HTTP Authentication Schemes" subregistry of the "Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry", as defined in [HTTP], Section 16.4 โจ. Here's the entry:
Authentication Scheme Name: PrivateToken
Reference: RFC 9577, Section 2
6.2. Privacy Pass Token Types Registry
IANA created a brand-new "Privacy Pass Token Types" registry on a new "Privacy Pass" page ๐. It lists identifiers for the issuance protocols defined for the Privacy Pass token authentication scheme ๐ฆ. These identifiers are 2-byte values, so the max possible value is 0xFFFF = 65535 ๐ข.
New registrations need to list these attributes:
Value: The 2-byte identifier for the algorithm.
Name: Name of the issuance protocol.
Token Structure: The contents of the token structure; see
Section 2.2.
Token Key Encoding: The encoding of the token-key parameter; see
Section 2.1.2.
TokenChallenge Structure: The contents of the TokenChallenge
structure; see Section 2.1.
Publicly Verifiable: A Y/N value indicating if the output tokens
have the public verifiability property; see Section 3.5 of
[ARCHITECTURE] for more details about this property.
Public Metadata: A Y/N value indicating if the output tokens can
contain public metadata; see Section 3.5 of [ARCHITECTURE] for
more details about this property.
Private Metadata: A Y/N value indicating if the output tokens can
contain private metadata; see Section 3.5 of [ARCHITECTURE] for
more details about this property.
Nk: The length in bytes of an output authenticator.
Nid: The length of the token key identifier.
Change Controller: The entity that is responsible for the definition
of the registration.
Reference: Where this algorithm is defined.
Notes: Any notes associated with the entry.
New entries get the Specification Required registration policy ([RFC8126], Section 4.6) ๐. Designated experts need to make sure the token type is defined for both token issuance and redemption ๐. They can also reject registrations that don't meet the security and privacy requirements for issuance protocols in Section 3.2 of [ARCHITECTURE] ๐ซ.
[ISSUANCE] defines entries for this registry ๐ .
6.2.1. Reserved Values
This document defines several reserved values that Clients and servers can use to send "greased" values in token challenges and redemptions ๐. This keeps implementations able to handle unknown token types gracefully, and the technique is inspired by [RFC8701] ๐ง .
Implementations SHOULD pick reserved values at random when putting them in greased messages ๐ฒ. Servers can include them in TokenChallenge structures, either as the only challenge when no real token type is wanted, or as one challenge in a list that also has real values ๐. Clients can include them in token structures when they can't present a real token ๐ซ . When using greased values, the contents of the token structure SHOULD be filled with random bytes ๐.
The initial contents of this registry are multiple reserved values, each with the attributes below, repeated for every registration ๐ฆ:
Value: 0x0000, 0x02AA, 0x1132, 0x2E96, 0x3CD3, 0x4473, 0x5A63,
0x6D32, 0x7F3F, 0x8D07, 0x916B, 0xA6A4, 0xBEAB, 0xC3F3, 0xDA42,
0xE944, 0xF057
Name: RESERVED
Token Structure: Random bytes
Token Key Encoding: Random bytes
TokenChallenge Structure: Random bytes
Publicly Verifiable: N/A
Public Metadata: N/A
Private Metadata: N/A
Nk: N/A
Nid: N/A
Change Controller: IETF
Reference: RFC 9577
Notes: None
7. References ๐
7.1. Normative References
Here are the normative references, in full ๐ค:
[ARCHITECTURE]
Davidson, A., Iyengar, J., and C. A. Wood, "The Privacy
Pass Architecture", RFC 9576, DOI 10.17487/RFC9576, June
2024, <https://www.rfc-editor.org/info/rfc9576>.
[HTTP] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke,
Ed., "HTTP Semantics", STD 97, RFC 9110,
DOI 10.17487/RFC9110, June 2022,
<https://www.rfc-editor.org/info/rfc9110>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
<https://www.rfc-editor.org/info/rfc4648>.
[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
Writing an IANA Considerations Section in RFCs", BCP 26,
RFC 8126, DOI 10.17487/RFC8126, June 2017,
<https://www.rfc-editor.org/info/rfc8126>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[SHS] National Institute of Standards and Technology, "Secure
Hash Standard (SHS)", NIST FIPS Publication 180-4,
DOI 10.6028/NIST.FIPS.180-4, August 2015,
<https://doi.org/10.6028/nist.fips.180-4>.
[TLS13] Rescorla, E., "The Transport Layer Security (TLS) Protocol
Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
<https://www.rfc-editor.org/info/rfc8446>.
[URI] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, DOI 10.17487/RFC3986, January 2005,
<https://www.rfc-editor.org/info/rfc3986>.
7.2. Informative References
okay so this is the bit where the doc points at the extra reading, bestie ๐โจ none of these are required to implement the thing, but they're the homework that makes it make sense ๐ค
[COOKIES] Bingler, S., Ed., West, M., Ed., and J. Wilander, Ed.,
"Cookies: HTTP State Management Mechanism", Work in
Progress, Internet-Draft, draft-ietf-httpbis-rfc6265bis-
14, 2 May 2024, <https://datatracker.ietf.org/doc/html/
draft-ietf-httpbis-rfc6265bis-14>.
[ISSUANCE] Celi, S., Davidson, A., Valdez, S., and C. A. Wood,
"Privacy Pass Issuance Protocols", RFC 9578,
DOI 10.17487/RFC9578, June 2024,
<https://www.rfc-editor.org/info/rfc9578>.
[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker,
"Randomness Requirements for Security", BCP 106, RFC 4086,
DOI 10.17487/RFC4086, June 2005,
<https://www.rfc-editor.org/info/rfc4086>.
[RFC8470] Thomson, M., Nottingham, M., and W. Tarreau, "Using Early
Data in HTTP", RFC 8470, DOI 10.17487/RFC8470, September
2018, <https://www.rfc-editor.org/info/rfc8470>.
[RFC8701] Benjamin, D., "Applying Generate Random Extensions And
Sustain Extensibility (GREASE) to TLS Extensibility",
RFC 8701, DOI 10.17487/RFC8701, January 2020,
<https://www.rfc-editor.org/info/rfc8701>.
[RFC9001] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure
QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021,
<https://www.rfc-editor.org/info/rfc9001>.
Appendix A. Test Vectors โจ๐งช
this appendix is the sample-answers page ๐ it's got test vectors for the HTTP authentication scheme in this doc, so you can check your code against known-good bytes. it's giving unit-test energy ๐
there are two kinds of test vectors here:
- Test vectors for the challenge and redemption protocols. Implementations can use these test vectors for verifying code that builds and encodes TokenChallenge structures, as well as code that produces a well-formed token bound to a TokenChallenge.
- Test vectors for the HTTP headers used for authentication. Implementations can use these test vectors for validating whether they parse HTTP authentication headers correctly to produce TokenChallenge structures and the other associated parameters, such as the token-key and max-age values.
A.1. Challenge and Redemption Structure Test Vectors ๐ฆ
this section has the test vectors for the challenge and redemption stuff from Sections 2.1 and 2.2. every vector lists these values:
token_type: The type of token issuance protocol, a value from Section 6.2. For these test vectors, token_type is 0x0002, corresponding to the issuance protocol discussed in Section 6 ("Issuance Protocol for Publicly Verifiable Tokens") of [ISSUANCE].issuer_name: The name of the Issuer in the TokenChallenge structure, represented as a hexadecimal string.redemption_context: The redemption context in the TokenChallenge structure, represented as a hexadecimal string.origin_info: The Origin information in the TokenChallenge structure, represented as a hexadecimal string.nonce: The nonce in the token structure, represented as a hexadecimal string.token_key_id: The public token key, encoded based on the corresponding token type, represented as a hexadecimal string.token_authenticator_input: The values in the token structure used to compute the token authenticator value, represented as a hexadecimal string.
the test vectors cover these TokenChallenge configurations:
- TokenChallenge with a single Origin and a non-empty redemption context.
- TokenChallenge with a single Origin and empty redemption context.
- TokenChallenge with an empty Origin and redemption context.
- TokenChallenge with an empty Origin and a non-empty redemption context.
- TokenChallenge with multiple Origins and a non-empty redemption context.
- TokenChallenge for greasing.
here they are, bestie ๐
// Test vector 1:
// token_type(0002), issuer_name(issuer.example),
// origin_info(origin.example), redemption_context(non-empty)
token_type: 0002
issuer_name: 6973737565722e6578616d706c65
redemption_context:
476ac2c935f458e9b2d7af32dacfbd22dd6023ef5887a789f1abe004e79bb5bb
origin_info: 6f726967696e2e6578616d706c65
nonce:
e01978182c469e5e026d66558ee186568614f235e41ef7e2378e6f202688abab
token_key_id:
ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708
token_authenticator_input: 0002e01978182c469e5e026d66558ee1865686
14f235e41ef7e2378e6f202688abab8e1d5518ec82964255526efd8f9db88205a
8ddd3ffb1db298fcc3ad36c42388fca572f8982a9ca248a3056186322d93ca147
266121ddeb5632c07f1f71cd2708
// Test vector 2:
// token_type(0002), issuer_name(issuer.example),
// origin_info(origin.example), redemption_context(empty)
token_type: 0002
issuer_name: 6973737565722e6578616d706c65
redemption_context:
origin_info: 6f726967696e2e6578616d706c65
nonce:
e01978182c469e5e026d66558ee186568614f235e41ef7e2378e6f202688abab
token_key_id:
ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708
token_authenticator_input: 0002e01978182c469e5e026d66558ee1865686
14f235e41ef7e2378e6f202688abab11e15c91a7c2ad02abd66645802373db1d8
23bea80f08d452541fb2b62b5898bca572f8982a9ca248a3056186322d93ca147
266121ddeb5632c07f1f71cd2708
// Test vector 3:
// token_type(0002), issuer_name(issuer.example),
// origin_info(), redemption_context(empty)
token_type: 0002
issuer_name: 6973737565722e6578616d706c65
redemption_context:
origin_info:
nonce:
e01978182c469e5e026d66558ee186568614f235e41ef7e2378e6f202688abab
token_key_id:
ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708
token_authenticator_input: 0002e01978182c469e5e026d66558ee1865686
14f235e41ef7e2378e6f202688ababb741ec1b6fd05f1e95f8982906aec161289
6d9ca97d53eef94ad3c9fe023f7a4ca572f8982a9ca248a3056186322d93ca147
266121ddeb5632c07f1f71cd2708
// Test vector 4:
// token_type(0002), issuer_name(issuer.example),
// origin_info(), redemption_context(non-empty)
token_type: 0002
issuer_name: 6973737565722e6578616d706c65
redemption_context:
476ac2c935f458e9b2d7af32dacfbd22dd6023ef5887a789f1abe004e79bb5bb
origin_info:
nonce:
e01978182c469e5e026d66558ee186568614f235e41ef7e2378e6f202688abab
token_key_id:
ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708
token_authenticator_input: 0002e01978182c469e5e026d66558ee1865686
14f235e41ef7e2378e6f202688ababb85fb5bc06edeb0e8e8bdb5b3bea8c4fa40
837c82e8bcaf5882c81e14817ea18ca572f8982a9ca248a3056186322d93ca147
266121ddeb5632c07f1f71cd2708
// Test vector 5:
// token_type(0002), issuer_name(issuer.example),
// origin_info(foo.example,bar.example),
// redemption_context(non-empty)
token_type: 0002
issuer_name: 6973737565722e6578616d706c65
redemption_context:
476ac2c935f458e9b2d7af32dacfbd22dd6023ef5887a789f1abe004e79bb5bb
origin_info: 666f6f2e6578616d706c652c6261722e6578616d706c65
nonce:
e01978182c469e5e026d66558ee186568614f235e41ef7e2378e6f202688abab
token_key_id:
ca572f8982a9ca248a3056186322d93ca147266121ddeb5632c07f1f71cd2708
token_authenticator_input: 0002e01978182c469e5e026d66558ee1865686
14f235e41ef7e2378e6f202688ababa2a775866b6ae0f98944910c8f48728d8a2
735b9157762ddbf803f70e2e8ba3eca572f8982a9ca248a3056186322d93ca147
266121ddeb5632c07f1f71cd2708
// Test vector 6:
// token_type(0000), structure(random_bytes)
token_type: 0000
token_authenticator_input: 000058405ad31e286e874cb42d0ef9d50461ae
703bb71a21178beb429c43c0effe587456d856f0f2bdfc216ef93d5c225e2a93e
84cb686e63919788087f7ab1054aa817f09dcb919a0ed6f90fe887e8b08cd1eee
44d5be8d813eda9f2656db61c932db8d73f8690604ded0120157923bbd19d5549
e639e4de07530aee1d370f5187b678685715bd878dde24346751eb532a87b71ea
40bbe5a13218658e303c648eb03817453690bfcbe8255081bf27ff0891cd02ee2
483e48a2c494bdef696f943fa992a65303292c25d0d3f62da86a70d0b020f0ff5
b90d0ff0f6abdb097d321fde04f3a1994e63bcd35a88c21236c7dc67600482223
f54b25e39a250439f27ecb5ae9eb8ed548a3ec1f1d6f510d08281929c8fe08834
2959e35ea9b3b6f6a96fc1a8edba4ed297f4cf02d0e4482b79a11f671745d7b7d
b120eddd8a4c2b6501bbc895b2160b8071615d9c1b18f32e056bfee29deac6a7d
6cf7b522a5badd63b9cb
A.2. HTTP Header Test Vectors ๐
okay so this bit is all about the actual HTTP headers ๐
each test vector is one or more challenges that together make up a WWW-Authenticate header (see Section 3.2 โจ). for every challenge you get the token-type, token-key, max-age, and token-challenge params, and every challenge also sneaks in an unknown (unspecified) parameter that implementations are meant to just ignore ๐
the params are indexed by their spot in the challenge list, so token-key-0 is the first challenge's token-key and token-key-1 is the second one's ๐ง
once the list is set, the wire-encoded WWW-Authenticate header gets listed at the end of each vector. the line folding is only there so everything fits on the page, and it's not how real requests look ๐
the last challenge in this list has Basic auth, a grease challenge, and a valid challenge for token type 0x0001 ๐ correct Client implementations ignore the Basic and grease challenges ๐ซถ
First up, the token-type 0x0002 challenge with its max-age and token-challenge:
token-type-0: 0x0002
token-key-0: 30820152303d06092a864886f70d01010a3030a00d300b060960864
8016503040202a11a301806092a864886f70d010108300b060960864801650304020
2a2030201300382010f003082010a0282010100cb1aed6b6a95f5b1ce013a4cfcab2
5b94b2e64a23034e4250a7eab43c0df3a8c12993af12b111908d4b471bec31d4b6c9
ad9cdda90612a2ee903523e6de5a224d6b02f09e5c374d0cfe01d8f529c500a78a2f
67908fa682b5a2b430c81eaf1af72d7b5e794fc98a3139276879757ce453b526ef9b
f6ceb99979b8423b90f4461a22af37aab0cf5733f7597abe44d31c732db68a181c6c
bbe607d8c0e52e0655fd9996dc584eca0be87afbcd78a337d17b1dba9e828bbd81e2
91317144e7ff89f55619709b096cbb9ea474cead264c2073fe49740c01f00e109106
066983d21e5f83f086e2e823c879cd43cef700d2a352a9babd612d03cad02db134b7
e225a5f0203010001
max-age-0: 10
token-challenge-0: 0002000e6973737565722e6578616d706c65208a3e83a33d9
8005d2f30bef419fa6bf4cd5c6005e36b1285bbb4ccd40fa4b383000e6f726967696
e2e6578616d706c65
and here's the single-challenge WWW-Authenticate header that goes with it, unknown param and all ๐ฆ
WWW-Authenticate: PrivateToken challenge="AAIADmlzc3Vlci5leGFtcGxlII
o-g6M9mABdLzC-9Bn6a_TNXGAF42sShbu0zNQPpLODAA5vcmlnaW4uZXhhbXBsZQ==",
token-key="MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqG
SIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEAyxrta2qV9bHOATpM
_KsluUsuZKIwNOQlCn6rQ8DfOowSmTrxKxEZCNS0cb7DHUtsmtnN2pBhKi7pA1I-beWi
JNawLwnlw3TQz-Adj1KcUAp4ovZ5CPpoK1orQwyB6vGvcte155T8mKMTknaHl1fORTtS
bvm_bOuZl5uEI7kPRGGiKvN6qwz1cz91l6vkTTHHMttooYHGy75gfYwOUuBlX9mZbcWE
7KC-h6-814ozfRex26noKLvYHikTFxROf_ifVWGXCbCWy7nqR0zq0mTCBz_kl0DAHwDh
CRBgZpg9IeX4PwhuLoI8h5zUPO9wDSo1Kpur1hLQPK0C2xNLfiJaXwIDAQAB",unknow
nChallengeAttribute="ignore-me", max-age="10"
Next, the same token-type 0x0002 challenge, now sitting next to a token-type 0x0001 challenge โจ here's the list:
token-type-0: 0x0002
token-key-0: 30820152303d06092a864886f70d01010a3030a00d300b060960864
8016503040202a11a301806092a864886f70d010108300b060960864801650304020
2a2030201300382010f003082010a0282010100cb1aed6b6a95f5b1ce013a4cfcab2
5b94b2e64a23034e4250a7eab43c0df3a8c12993af12b111908d4b471bec31d4b6c9
ad9cdda90612a2ee903523e6de5a224d6b02f09e5c374d0cfe01d8f529c500a78a2f
67908fa682b5a2b430c81eaf1af72d7b5e794fc98a3139276879757ce453b526ef9b
f6ceb99979b8423b90f4461a22af37aab0cf5733f7597abe44d31c732db68a181c6c
bbe607d8c0e52e0655fd9996dc584eca0be87afbcd78a337d17b1dba9e828bbd81e2
91317144e7ff89f55619709b096cbb9ea474cead264c2073fe49740c01f00e109106
066983d21e5f83f086e2e823c879cd43cef700d2a352a9babd612d03cad02db134b7
e225a5f0203010001
max-age-0: 10
token-challenge-0: 0002000e6973737565722e6578616d706c65208a3e83a33d9
8005d2f30bef419fa6bf4cd5c6005e36b1285bbb4ccd40fa4b383000e6f726967696
e2e6578616d706c65
token-type-1: 0x0001
token-key-1: ebb1fed338310361c08d0c7576969671296e05e99a17d7926dfc28a
53fabd489fac0f82bca86249a668f3a5bfab374c9
max-age-1: 10
token-challenge-1: 0001000e6973737565722e6578616d706c65208a3e83a33d9
8005d2f30bef419fa6bf4cd5c6005e36b1285bbb4ccd40fa4b383000e6f726967696
e2e6578616d706c65
and the two-challenge WWW-Authenticate header for that list ๐ซง
WWW-Authenticate: PrivateToken challenge="AAIADmlzc3Vlci5leGFtcGxlII
o-g6M9mABdLzC-9Bn6a_TNXGAF42sShbu0zNQPpLODAA5vcmlnaW4uZXhhbXBsZQ==",
token-key="MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqG
SIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEAyxrta2qV9bHOATpM
_KsluUsuZKIwNOQlCn6rQ8DfOowSmTrxKxEZCNS0cb7DHUtsmtnN2pBhKi7pA1I-beWi
JNawLwnlw3TQz-Adj1KcUAp4ovZ5CPpoK1orQwyB6vGvcte155T8mKMTknaHl1fORTtS
bvm_bOuZl5uEI7kPRGGiKvN6qwz1cz91l6vkTTHHMttooYHGy75gfYwOUuBlX9mZbcWE
7KC-h6-814ozfRex26noKLvYHikTFxROf_ifVWGXCbCWy7nqR0zq0mTCBz_kl0DAHwDh
CRBgZpg9IeX4PwhuLoI8h5zUPO9wDSo1Kpur1hLQPK0C2xNLfiJaXwIDAQAB",unknow
nChallengeAttribute="ignore-me", max-age="10", PrivateToken challeng
e="AAEADmlzc3Vlci5leGFtcGxlIIo-g6M9mABdLzC-9Bn6a_TNXGAF42sShbu0zNQPp
LODAA5vcmlnaW4uZXhhbXBsZQ==", token-key="67H-0zgxA2HAjQx1dpaWcSluBem
aF9eSbfwopT-r1In6wPgryoYkmmaPOlv6s3TJ",unknownChallengeAttribute="ig
nore-me", max-age="10"
Last one! This vector has a token-type 0x0000 challenge (no max-age on that one ๐), the valid token-type 0x0001 challenge, and a grease challenge tucked in with Basic auth ๐
token-type-0: 0x0000
token-key-0: 856de3c710b892e7cca1ae5eb121af42ca8e779137a11224228c9b9
9b0729bf84d5057d030000309b8f0d06ccffa17561f9eacd4c312e985a6bc60ffbea
0610264dcb1726255313da81d665692686a1d8644f1516bf612cea009e6dff6d9a9a
959fb538e1b5b2343c092992942382bdde22d5b324b1e4618ed21d7806286c2ce
token-challenge-0: 0000acc3b25795c636fd9dd8b12982394abba8777d35978e8
77fc8848892a217233045ac25a3d55c07c54efe6372973fee0073e77fc61bf19ab88
0f20edf5d627502
token-type-1: 0x0001
token-key-1: ebb1fed338310361c08d0c7576969671296e05e99a17d7926dfc28a
53fabd489fac0f82bca86249a668f3a5bfab374c9
max-age-1: 10
token-challenge-1: 0001000e6973737565722e6578616d706c65208a3e83a33d9
8005d2f30bef419fa6bf4cd5c6005e36b1285bbb4ccd40fa4b383000e6f726967696
e2e6578616d706c65
and its WWW-Authenticate header, grease and Basic included โจ
WWW-Authenticate: Basic realm="grease", PrivateToken challenge="AACs
w7JXlcY2_Z3YsSmCOUq7qHd9NZeOh3_IhIiSohcjMEWsJaPVXAfFTv5jcpc_7gBz53_G
G_GauIDyDt9dYnUC", token-key="hW3jxxC4kufMoa5esSGvQsqOd5E3oRIkIoybmbB
ym_hNUFfQMAADCbjw0GzP-hdWH56s1MMS6YWmvGD_vqBhAmTcsXJiVTE9qB1mVpJoah2
GRPFRa_YSzqAJ5t_22ampWftTjhtbI0PAkpkpQjgr3eItWzJLHkYY7SHXgGKGws4=",
PrivateToken challenge="AAEADmlzc3Vlci5leGFtcGxlIIo-g6M9mABdLzC-9Bn6
a_TNXGAF42sShbu0zNQPpLODAA5vcmlnaW4uZXhhbXBsZQ==", token-key="67H-0z
gxA2HAjQx1dpaWcSluBemaF9eSbfwopT-r1In6wPgryoYkmmaPOlv6s3TJ",unknownC
hallengeAttribute="ignore-me", max-age="10"
Authors' Addresses ๐
Tommy Pauly
Apple Inc.
One Apple Park Way
Cupertino, California 95014
United States of America
Email: tpauly@apple.com
Steven Valdez
Google LLC
Email: svaldez@chromium.org
Christopher A. Wood
Cloudflare
Email: caw@heapingbits.net
๐ฆ where this page comes from
- ietf: rfc9577 2024-06
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms