RFC 8473

Token Binding over HTTP

πŸ“… published October 2018, from ietf

πŸ“œ Token Binding over HTTP (RFC 8473) πŸŽ€

Okay bestie, let's get into it! ✨ This is RFC 8473, and it's giving security token glow-up πŸ’…. It's on the Standards Track, so it's an official Internet standard, and it came out in October 2018. Its authors are A. Popov, M. Nystroem (Microsoft Corp.), D. Balfanz (Ed.) and N. Harper (Google Inc.), and J. Hodges (Kings Mountain Systems) 🧚. It's a companion to RFC 8471, "The Token Binding Protocol Version 1.0" πŸ’œ. It doesn't obsolete or update any other RFC, so it's all its own thing 🌸.

Here's the vibe: the whole point is to lock security tokens (like cookies and OAuth tokens) to a specific TLS connection, so an attacker can't just copy one and use it somewhere else πŸ”’πŸ¦‹. Obsessed. 😭


Status of This Memo ✨

This is an Internet Standards Track document πŸŽ€.

It's a product of the Internet Engineering Task Force (IETF) 🌈. It represents the consensus of the IETF community, received public review, and got approved for publication by the Internet Engineering Steering Group (IESG) πŸ‘‘. For more info on Internet Standards, check Section 2 of RFC 7841 πŸ“–.

You can find the current status, any errata, and how to give feedback at https://www.rfc-editor.org/info/rfc8473 πŸ’–.

Copyright (c) 2018 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. Read those carefully, bestie, because they spell out your rights and restrictions. Code components pulled from this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come with no warranty, as the Simplified BSD License describes 🫢.

Table of Contents 🧚

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
  1.1.  Requirements Language . . . . . . . . . . . . . . . . . .   3
2.  The Sec-Token-Binding HTTP Request Header Field . . . . . . .   4
  2.1.  HTTPS Token Binding Key-Pair Scoping  . . . . . . . . . .   5
3.  TLS Renegotiation . . . . . . . . . . . . . . . . . . . . . .   6
4.  First-Party Use Cases . . . . . . . . . . . . . . . . . . . .   7
5.  Federation Use Cases  . . . . . . . . . . . . . . . . . . . .   7
  5.1.  Introduction  . . . . . . . . . . . . . . . . . . . . . .   7
  5.2.  Overview  . . . . . . . . . . . . . . . . . . . . . . . .   8
  5.3.  HTTP Redirects  . . . . . . . . . . . . . . . . . . . . .  10
  5.4.  Negotiated Key Parameters . . . . . . . . . . . . . . . .  12
  5.5.  Federation Example  . . . . . . . . . . . . . . . . . . .  13
6.  Implementation Considerations . . . . . . . . . . . . . . . .  15
7.  Security Considerations . . . . . . . . . . . . . . . . . . .  16
  7.1.  Security Token Replay . . . . . . . . . . . . . . . . . .  16
  7.2.  Sensitivity of the Sec-Token-Binding Header . . . . . . .  16
  7.3.  Securing Federated Sign-On Protocols  . . . . . . . . . .  17
8.  Privacy Considerations  . . . . . . . . . . . . . . . . . . .  20
  8.1.  Scoping of Token Binding Key Pairs  . . . . . . . . . . .  20
  8.2.  Lifetime of Token Binding Key Pairs . . . . . . . . . . .  20
  8.3.  Correlation . . . . . . . . . . . . . . . . . . . . . . .  21
9.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  22
10. References  . . . . . . . . . . . . . . . . . . . . . . . . .  22
  10.1.  Normative References . . . . . . . . . . . . . . . . . .  22
  10.2.  Informative References . . . . . . . . . . . . . . . . .  23
Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . . .  25
Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  25

1. Introduction πŸ¦‹

Okay so the Token Binding protocol in [RFC8471] gives a Token Binding ID to a TLS connection between a client and a server πŸ”—. That ID is built from the public key of a private-public key pair πŸ”‘, and the client proves it has the matching private key πŸ’…. This key pair is long-lived 🌷. Later TLS connections between the same client and server keep the same Token Binding ID, unless something specifically resets it, like the user doing it on purpose πŸ™ˆ.

Here's the glow-up part ✨. When a server hands a client a security token (say an HTTP cookie or an OAuth token [RFC6749]), it can put the Token Binding ID inside the token. That locks the token to TLS connections between that exact client and server, and it protects the token from abuse like reuse or impersonation by attackers πŸ›‘οΈπŸ’–. Iconic. πŸ‘‘

[RFC8471] defines a message format for setting up a Token Binding ID, but it doesn't say how that message gets tucked into higher-level protocols πŸŽ€. So this spec fills that gap by defining how TokenBindingMessages are embedded in HTTP, for both HTTP/1.1 [RFC7230] and HTTP/2 [RFC7540] 🌈. Heads up: TokenBindingMessages only exist when the transport uses TLS. So Token Binding over HTTP only works when HTTP runs on top of TLS, which people usually call HTTPS [RFC2818] πŸ”’.

HTTP clients set up a Token Binding ID with a server by including a special HTTP header field in their requests πŸ“¨. The value of that header is a base64url-encoded TokenBindingMessage 🧚.

A single TokenBindingMessage can set up several Token Binding IDs with the server, because it can hold multiple TokenBinding structures πŸ“. By default, a client sets up a Provided Token Binding ID with the server, which is a Token Binding ID the client will keep using with that server πŸ’œ. Under certain conditions, the client can also add a Referred Token Binding ID to the TokenBindingMessage. That's a Token Binding ID the client is using with a different server than the one receiving the message, which is super useful for federation scenarios 🌸✨.

1.1. Requirements Language πŸ’…

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 interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here πŸŽ€. (Yes, I'm being picky, but that's the rule, periodt 😀.)


2. The Sec-Token-Binding HTTP Request Header Field 🌷

Once a client and server have agreed on the Token Binding protocol over HTTP/1.1 or HTTP/2 (see [RFC8471] and [RFC8472]), clients MUST include a Sec-Token-Binding header field in their HTTP requests, and they MUST include only one such header field per HTTP request πŸ“¨. Also, the Sec-Token-Binding header field MUST NOT show up in HTTP responses πŸ™…β€β™€οΈ. The ABNF for this header field follows the style of [RFC7230], and you can also peek at Section 8.3 of [RFC7231] 🧚:

Sec-Token-Binding = EncodedTokenBindingMessage

The header field name is Sec-Token-Binding. Its single value, EncodedTokenBindingMessage, is a base64url encoding of one TokenBindingMessage from [RFC8471] πŸ”. The base64url encoding uses the URL and filename safe character set from Section 5 of [RFC4648], drops all trailing padding characters (the = signs), and has no line breaks, whitespace, or other extra characters πŸ¦‹.

Here's an example πŸ’–:

Sec-Token-Binding: AIkAAgBBQFzK4_bhAqLDwRQxqJWte33d7hZ0hZWHwk-miKPg4E\
                   9fcgs7gBPoz-9RfuDfN9WCw6keHEw1ZPQMGs9CxpuHm-YAQM_j\
                   aOwwej6a-cQBGU7CJpUHOvXG4VvjNq8jDsvta9Y8_bPEPj25Gg\
                   mKiPjhJEtZA6mJ_9SNifLvVBTi7fR9wSAAAA

(Note that the backslashes and line breaks are just there to make it easier to read. They aren't part of the actual encoded message πŸ™ˆ.)

If the server gets more than one Sec-Token-Binding header field in a single HTTP request, the server MUST reject the message with a 400 (Bad Request) HTTP status code 🚫. On top of that, the Sec-Token-Binding header field:

  • SHOULD NOT be stored by origin servers on PUT requests πŸ™…β€β™€οΈ,
  • MAY be listed by a server in a Vary response header field 🌈, and
  • MUST NOT be used in HTTP trailers πŸ’€.

The TokenBindingMessage MUST contain exactly one TokenBinding structure whose TokenBindingType value is provided_token_binding πŸ“. That structure MUST be signed with the Token Binding private key the client uses for connections between itself and the server the HTTP request goes to. (Clients use different Token Binding key pairs for different servers. See Section 2.1 below πŸ”‘.) The Token Binding ID set up by this TokenBinding is called a "Provided Token Binding ID" πŸ’œ.

The TokenBindingMessage MAY also contain exactly one TokenBinding structure whose TokenBindingType value is referred_token_binding, as covered in Section 5.3 🌸. Alongside that structure, or instead of it, the TokenBindingMessage MAY contain other TokenBinding structures 🧚. Which ones depends on the use case, and those use cases are outside the scope of this spec ✨.

The server validates a TokenBindingMessage as described in Section 4.2 ("Server Processing Rules") of [RFC8471] πŸ”. If validation fails and a Token Binding gets rejected, the server MUST also reject any bound tokens tied to it 🚫. HTTP requests with invalid tokens MUST be rejected πŸ™…β€β™€οΈ. In that case, the server application MAY return HTTP status code 400 (Bad Request), or it can carry on with an application-specific "invalid token" response (like sending the client off to log in again with a different token), or it can terminate the connection πŸ’….

In HTTP/2, the client SHOULD use header compression [RFC7541] so it doesn't have to keep repeating the same header field in later HTTP requests πŸ—œοΈπŸ’œ.

Part 1 of 6 done, bestie! πŸŽ€ More parts are coming, so stay tuned 🫢✨

2.1. HTTPS Token Binding Key-Pair Scoping πŸŽ€

okay so HTTPS gets used with all kinds of application protocols and app contexts, in all kinds of ways 🌸 General-purpose web browsing is one of those HTTP-based contexts, and in there, HTTP cookies [RFC6265] are the usual move for state management, including client authentication. A related-but-different example is OAuth tokens [RFC6749], which manage authorization for third-party apps getting at resources. The scoping rules for these two can differ. Cookie scoping is concisely specified in [RFC6265], but OAuth is a framework that defines various token types with various scopings, and some of those get decided by the surrounding application πŸ’…

The scoping of Token Binding key pairs that web browsers generate to bind HTTP cookies MUST be no wider than the granularity of a "registered domain" (aka "effective top-level domain + 1", or "eTLD+1") ✨ An origin's "registered domain" is the origin's host's public suffix plus the label to its left (where "public suffix" is defined in the "NOTE:" paragraph in Section 5.3 of [RFC6265] as "a domain that is controlled by a public registry"). For example, for "https://www.example.com", the public suffix (eTLD) is "com" and the registered domain (eTLD+1) is "example.com". User Agents SHOULD use an up-to-date public suffix list, such as the one Mozilla maintains [PSL] πŸ¦‹

So in practice, a Token Binding key pair's scope is no larger than the scope of a cookie that a web browser allows. If a web browser restricts cookies to something narrower than registered domains, the scope of Token Binding key pairs MAY also be narrower. This goes for first-party use cases and for the federation use cases in this specification (Section 5) 🌈

Key pairs used to bind other application tokens, like OAuth tokens or "OpenID Connect" ID Tokens [OpenID.Core], SHOULD follow that same eTLD+1 scoping rule for those tokens when they're used in first-party or federation scenarios. Applications other than web browsers MAY use different key-pair scoping rules. See also Section 8.1 below πŸ’œ

Scoping rules for other HTTP-based application contexts are outside the scope of this specification πŸ™ˆ


3. TLS Renegotiation

Token Binding over HTTP/1.1 [RFC7230] can be combined with TLS renegotiation πŸ”₯ In this case, renegotiation MUST only occur between a client's HTTP request and the server's response, the client MUST NOT send any pipelined requests, and the client MUST NOT initiate renegotiation. (So basically, the client may only send a renegotiation ClientHello in response to the server's HelloRequest.) These conditions make sure that both the client and the server can clearly tell which TLS Exported Keying Material value [RFC5705] to use when generating or verifying the TokenBindingMessage. They also stop a TokenBindingMessage from getting split across TLS renegotiation boundaries because of TLS message fragmentation; see Section 6.2.1 of [RFC5246] πŸ‘‘

(Note: This document deals with TLS 1.2 and therefore refers to RFC 5246 (which has been obsoleted by RFC 8446); [TOKENBIND-TLS13] addresses Token Binding in TLS 1.3.) 🫢

4. First-Party Use Cases

okay this is the "same-site" one πŸ“ In a first-party use case (also called a "same-site" use case), an HTTP server hands a client a security token, like a cookie, and expects the client to send it back later, e.g., to authenticate. Binding the security token to the TLS connection between client and server protects it from misuse, because the server can spot when the token gets replayed inappropriately, e.g., over other TLS connections. Iconic protection, honestly πŸ›‘οΈ

See Section 5 of [RFC8471] for general guidance on binding security tokens and validating them afterward πŸ’…


5. Federation Use Cases

5.1. Introduction

okay the privacy angle here is so good 😭 For privacy reasons, clients use different Token Binding key pairs to establish Provided Token Binding IDs with different servers. That means a server can't bind a security token (like an OAuth token or an OpenID Connect ID Token [OpenID.Core]) to a TLS connection the client has with a different server. This is still a common need in federation. For example, an Identity Provider may want to issue an identity token to a client and cryptographically bind that token to the TLS connection between the client and a Relying Party πŸ¦‹

So here's how we get it done ✨ The shared idea is that a server (called the "Token Consumer" in this document) signals to the client that it should reveal the Provided Token Binding ID it uses with itself to another server (called the "Token Provider" in this document). The client also always reveals it the same way: it uses the Token Binding protocol [RFC8471] and includes a TokenBinding structure in the Sec-Token-Binding HTTP header field defined above. What changes between the mechanisms is how the Token Consumer tells the client to reveal the Token Binding ID to the Token Provider. We're specifying one mechanism here, which works for redirect-based interactions between Token Consumers and Token Providers 🌸

   Client                        Token Consumer         Token Provider
   +--------+                        +----+                +-----+
   | Client |                        | TC |                | TP  |
   +--------+                        +----+                +-----+
       |                               |                      |
       |                               |                      |
       |                               |                      |
       | Client interacts w/TC         |                      |
       | using TokenBindingID TBID1:   |                      |
       | TBMSG[[provided_token_binding,|                      |
       |        TBID1, signature]]     |                      |
       |------------------------------>|                      |
       |                               |                      |
       | Client interacts w/TP                                |
       | using TokenBindingID TBID2:                          |
       | TBMSG[[provided_token_binding,                       |
       |        TBID2, signature]]                            |
       |----------------------------------------------------->|
       |                                                      |
       |                               |                      |
       | TC signals permission to      |                      |
       | reveal TBID1 to TP            |                      |
       |<------------------------------|                      |
       |                               |                      |
       |                                                      |
       | Client interacts w/TP                                |
       | using TokenBindingID TBID1 and TBID2:                |
       | TBMSG[[provided_token_binding,                       |
       |        TBID2, signature],                            |
       |       [referred_token_binding,                       |
       |        TBID1, signature]]                            |
       |----------------------------------------------------->|
       |                                                      |
       |                               |                      |
       |                               |                      |

5.2. Overview

okay so in a federated sign-on protocol, an Identity Provider issues an identity token to a client, and the client sends that token to a Relying Party to authenticate itself. Examples are OpenID Connect (where the identity token is called an "ID Token") and the Security Assertion Markup Language (SAML) [OASIS.saml-core-2.0-os] (where the identity token is a SAML assertion) πŸ’–

To better protect the identity token, the Identity Provider may want to bind it to the TLS connection between the client and the Relying Party, so only that client can use it πŸ”’ The Relying Party then compares the Token Binding ID (or a cryptographic hash of it) in the identity token with the Token Binding ID (or a hash of it) of the TLS connection between itself and the client.

This is one example of a federation scenario, which more generally goes like this:

  • A Token Consumer causes the client to send a token request to the Token Provider. The goal is for the client to get a token and then use it with the Token Consumer.
  • The client delivers the token request to the Token Provider.
  • The Token Provider issues the token. The token is issued for the specific Token Consumer that requested it, which stops malicious Token Consumers from using tokens meant for other Token Consumers. The token is, however, typically a bearer token, meaning any client can use it with the Token Consumer, not just the client it was issued to πŸ™…β€β™€οΈ
  • So, in the previous step, the Token Provider may want to include in the token the Token Binding ID (or a cryptographic hash of it) that the client uses when talking to the Token Consumer, binding the token to the client's Token Binding key pair 🧚 The client proves it possesses the private key when communicating with the Token Consumer through the Token Binding protocol [RFC8471], and it uses the corresponding public key of that key pair as a component of the Token Binding ID. Comparing the Token Binding ID in the token with the Token Binding ID established with the client lets the Token Consumer verify that the token was sent to it by the legitimate client ✨
  • For the Token Provider to include the Token Binding ID in the token, the Token Binding ID between the client and the Token Consumer has to be shared with the Token Provider along with the token request. Sharing a Token Binding ID involves proving possession of a private key, and that's described in the Token Binding protocol [RFC8471] πŸ”‘

The client will only perform this last operation if the Token Consumer asks it to do so πŸ‘€

Below, we specify how Token Consumers can signal this request in redirect-based federation protocols. Note that this assumes the federated sign-on flow starts at the Token Consumer or, at the very least, includes a redirect from the Token Consumer to the Token Provider. Specifying similar mechanisms for flows without such redirects is outside the scope of this document 🌈

5.3. HTTP Redirects ✨

Okay so, when a Token Consumer (TC) redirects the client to a Token Provider just to deliver the token request, it SHOULD pop an Include-Referred-Token-Binding-ID header field into its HTTP response πŸ’… The ABNF for this header is (per the style of [RFC7230]; see also Section 8.3 of [RFC7231]):

Include-Referred-Token-Binding-ID = "true"

The header field name is "Include-Referred-Token-Binding-ID", and the field value true is case insensitive. So for example:

Include-Referred-Token-Binding-ID: true

This header is basically the client's permission slip πŸŽ€ It signals that the client should reveal, to the Token Provider, the Token Binding ID it's using with the Token Consumer. If this header is NOT there, the client won't disclose anything about the Token Binding it has with the Token Consumer to the Token Provider. Private girl math, honestly πŸ™ˆ

As illustrated in Section 5.5, when a client gets this header field, it should take the TokenBindingID [RFC8471] of the provided TokenBinding from the referrer and build a referred TokenBinding out of it. That referred TokenBinding then goes into the TokenBindingMessage in the redirect request. So the Token Binding message in the redirect request to the Token Provider ends up with two bindings: one provided, and one referred, the referred one made from the binding between the client and the Token Consumer πŸ¦‹

When a client receives the Include-Referred-Token-Binding-ID header, it includes the referred Token Binding even if both the Token Provider and the Token Consumer fall under the same eTLD+1, and the provided and Referred Token Binding IDs are the same. Yes, even then. No skipping πŸ’–

The referred Token Binding is only sent in the initial request that comes out of the HTTP response with the Include-Referred-Token-Binding-ID header. Should the response to that initial request be another redirect, the original referred Token Binding is no longer included in subsequent requests. (A new referred Token Binding may be included if the redirecting endpoint itself responded with an Include-Referred-Token-Binding-ID response header. Main character energy, new scene, new binding 🌸)

If the Include-Referred-Token-Binding-ID header field shows up in a response to a request that did NOT include the Sec-Token-Binding header field, the client MUST ignore the Include-Referred-Token-Binding-ID header field. Not my vibe, so it gets ignored πŸ™…β€β™€οΈ

This header only means something if the HTTP status code is a redirection code (300-399). For any other status codes, the client MUST ignore it. As described in Section 2, if the client supports the Token Binding protocol and has negotiated it with both the Token Consumer and the Token Provider, it sends the Sec-Token-Binding header field to the Token Provider with each HTTP request 🧚

The TokenBindingMessage included in the redirect request to the Token Provider SHOULD contain a TokenBinding with a TokenBindingType value of referred_token_binding. If it's included, this TokenBinding MUST be signed with the Token Binding private key the client uses for connections between itself and the Token Consumer. More specifically, that's the server that issued the Include-Referred-Token-Binding-ID response header field. The Token Binding ID established by this TokenBinding is called a "Referred Token Binding ID" ✨

As described above, the TokenBindingMessage MUST additionally contain a Provided Token Binding ID. That's a TokenBinding structure with a TokenBindingType value of provided_token_binding, and it MUST be signed with the Token Binding private key the client uses for connections between itself and the Token Provider. More specifically, that's the server the token request is being sent to 🫢

Now, if for some deployment-specific reason the initial Token Provider ("TP1") needs to redirect the client to another Token Provider ("TP2") instead of straight back to the Token Consumer, the header fields in this spec can handle it like this ("the redirect-chain approach") 🌈

First, the Token Consumer ("TC") redirects the client to TP1, same as above. When TP1 gets the client's request, which has a TokenBindingMessage containing both provided and referred TokenBindings (for TP1 and TC, respectively), TP1 replies with a redirect response. That response does two things: (1) it includes the Include-Referred-Token-Binding-ID header field, and (2) it points the client at TP2. The client then follows the same pattern and sends TP2 a request with a TokenBindingMessage that has both provided and referred TokenBindings (for TP2 and TP1, respectively). This pattern can keep going to more Token Providers if needed. In that case, TP2 issues a security token bound to the client's TokenBinding with TP1, then sends the client a redirect response pointing back to TP1. Then TP1 builds a security token for the Token Consumer, bound to the TC's referred TokenBinding that was passed along earlier, and sends the client a redirect response pointing to the TC, with the bound security token inside. Chain reaction, but make it cute πŸ¦‹πŸ‘‘

The above is only a non-normative example, bestie. The details depend on the deployment context. Other approaches are possible, but they're outside the scope of this specification πŸ€·β€β™€οΈ

5.4. Negotiated Key Parameters πŸ”₯

The TLS extension for Token Binding protocol negotiation [RFC8472] lets the server and client negotiate the parameters (signature algorithm, length) of the Token Binding key pair. It's possible that the Token Binding ID used between the client and the Token Consumer, and the Token Binding ID used between the client and the Token Provider, use different key parameters. Even so, the client MUST use the key parameters negotiated with the Token Consumer in the referred_token_binding TokenBinding of the TokenBindingMessage, even if those key parameters are different from the ones negotiated with the server the header field is sent to. Loyalty to the TC, periodt πŸ’œ

Token Providers SHOULD support all the Token Binding key parameters specified in [RFC8471]. If a Token Provider doesn't support the key parameters specified in the referred_token_binding TokenBinding in the TokenBindingMessage, it MUST NOT issue a bound token. No support, no bound token. Iconic boundaries πŸ’€βœ¨

5.5. Federation Example ✨

okay so this diagram is giving classic browser SSO πŸ’… It's a typical HTTP redirect-based web browser single sign-on (SSO) profile (Section 4.1 of [OASIS.saml-prof-2.0-os]) (no artifact, no callbacks), and it shows how a TLS Token Binding ID can get bound into an OpenID Connect ID Token. Main character energy πŸ¦‹

Here's the legend first so you can decode everything else πŸŽ€

+------------+------------------------------------------------------+
| EKM:       | TLS Exported Keying Material [RFC5705]               |
|            |                                                      |
| {EKMn}Ksm: | EKM for server "n", signed by the private key of     |
|            | TBID "m", where "n" must represent the server        |
|            | receiving the ETBMSG.  If a conveyed TB's type is    |
|            | provided_token_binding, then m = n, else if TB's     |
|            | type is referred_token_binding, then m != n.  For    |
|            | example, see step 1b in the diagram below.           |
|            |                                                      |
| ETBMSG:    | "Sec-Token-Binding" HTTP header field conveying an   |
|            | EncodedTokenBindingMessage, in turn conveying        |
|            | TokenBinding (TB)struct(s), e.g., ETBMSG[[TB]] or    |
|            | ETBMSG[[TB1],[TB2]]                                  |
|            |                                                      |
| ID Token:  | the ID Token in OpenID Connect.  It is the semantic  |
|            | equivalent of a SAML "authentication assertion".     |
|            | "ID Token w/TBIDn" denotes a "token bound" ID Token  |
|            | containing TBIDn.                                    |
|            |                                                      |
| Ks and Kp: | private (aka secret) key and public key,             |
|            | respectively, of the client-side Token Binding key   |
|            | pair                                                 |
|            |                                                      |
| OIDC:      | OpenID Connect                                       |
|            |                                                      |
| TB:        | TokenBinding struct containing a signed EKM, TBID,   |
|            | and TB type, e.g.,                                   |
|            | [{EKM1}Ks1,TBID1,provided_token_binding]             |
|            |                                                      |
| TBIDn:     | Token Binding ID for client and server n's token-    |
|            | bound TLS association.  TBIDn contains Kpn.          |
+------------+------------------------------------------------------+

And here's the flow itself, step by step 🧚

Client, aka                Token Consumer, aka    Token Provider, aka
User Agent                 OpenID Client,         OpenID Provider,
                           OIDC Relying Party,    OIDC Provider,
                           SAML Relying Party     SAML Identity Provider
                           [ server "1" ]         [ server "2" ]
+--------+                       +----+                 +-----+
| Client |                       | TC |                 | TP  |
+--------+                       +----+                 +-----+
    |                               |                      |
    |                               |                      |
    |                               |                      |
    | 0. Client interacts w/TC      |                      |
    | over HTTPS, establishes Ks1 and Kp1, TBID1           |
    | ETBMSG[[{EKM1}Ks1,TBID1,provided_token_binding]]     |
    |------------------------------>|                      |
    |                               |                      |
    |                               |                      |
    |                               |                      |
    | 1a. OIDC ID Token request, aka|                      |
    | "Authentication Request", conveyed with              |
    | an HTTP response header field of                     |
    | Include-Referred-Token-Binding-ID:true.              |
    | Any security-relevant cookies |                      |
    | should contain TBID1.         |                      |
  +<- - - - - - - - - - - - - - - - |                      |
  . | (redirect to TP via 301, 302, |                      |
  . |  303, 307, or 308)            |                      |
  . |                               |                      |
  +------------------------------------------------------->|
    | 1b. opens HTTPS w/TP,                                |
    | establishes Ks2, Kp2, TBID2;                         |
    | sends a GET or POST with                             |
    | ETBMSG[[{EKM2}Ks2,TBID2,provided_token_binding],     |
    |        [{EKM2}Ks1,TBID1,referred_token_binding]]     |
    | as well as the ID Token request                      |
    |                               |                      |
    |                               |                      |
    |                               |                      |
    | 2. user authentication (if applicable;               |
    |    methods vary; particulars are out of scope)       |
    |<====================================================>|
    | (TP generates ID Token for TC containing TBID1; may  |
    |  also set cookie(s) containing TBID2 and/or TBID1;   |
    |  details vary; particulars are out of scope)         |
    |                               |                      |
    |                               |                      |
    |                               |                      |
    | 3a. ID Token containing Kp1, issued for TC,          |
    |    conveyed via OIDC "Authentication Response"       |
  +<- - - - - - - - - - - - - - - - - - - - - - - - - - - -|
  . |   (redirect to TC)            |                      |
  . |                               |                      |
  . |                               |                      |
  +-------------------------------->|                      |
    | 3b. HTTPS GET or POST with                           |
    | ETBMSG[[{EKM1}Ks1,TBID1,provided_token_binding]]     |
    | conveying an Authentication Response containing      |
    | an ID Token w/TBID1, issued for TC                   |
    |                               |                      |
    |                               |                      |
    |                               |                      |
    | 4. user is signed on; any security-relevant cookie(s)|
    | that is set SHOULD contain TBID1                     |
    |<------------------------------|                      |
    |                               |                      |
    |                               |                      |

6. Implementation Considerations πŸ› οΈ

HTTPS-based apps can have multi-party use cases that aren't just the HTTP redirect-based signaling and conveyance of referred Token Bindings we just saw in Section 5.3, or they can have those plus other stuff πŸ’–

So, token binding implementations should provide APIs that let apps generate Token Binding messages containing Token Binding IDs of different application-specified Token Binding types, which then get conveyed by the Sec-Token-Binding header field πŸŽ€

BUT (and this is a big but πŸ™ˆ) Token Binding implementations MUST only convey Token Binding IDs to servers if an application signals them to do so. Signaling mechanisms other than the Include-Referred-Token-Binding-ID HTTP response header field are possible, but those are outside the scope of this specification 🌸

NOTE: See Section 8 ("Privacy Considerations") for privacy guidance regarding the use of this functionality. πŸ”’

7. Security Considerations πŸ”

7.1. Security Token Replay πŸ’€

okay this part is seriously important, bestie 😭 The whole point of the federated Token Binding mechanisms is to stop attackers from exporting and replaying tokens used in protocols between the client and the Token Consumer, so they can't pretend to be real users and sneak into protected resources. Bound tokens can still get replayed by any malware sitting on a client (and a server might not even be able to detect it, yikes), but to export bound tokens to other machines and replay them successfully, attackers ALSO need to export the matching Token Binding private keys. Those keys are high-value assets, so they SHOULD be strongly protected, ideally by generating them in a hardware security module that prevents key export πŸ”₯

This is a special case of the scenario described in Section 7.1 ("Security Token Replay") of [RFC8471] πŸ‘‘

7.2. Sensitivity of the Sec-Token-Binding Header ✨

okay bestie, the whole point of Token Binding is to convince the server that the client who started the TLS connection actually controls a certain key pair πŸ”. For the server to draw that conclusion correctly after processing the Sec-Token-Binding header field, some secrecy and integrity requirements have to be met πŸ’….

For example, the client must keep its Token Binding private key secret 🀫. If the private key isn't secret, another actor in the system could make a valid Sec-Token-Binding header field and impersonate the client 😱. That can make the main purpose of the protocol (binding bearer tokens to certain clients) totally moot πŸ’€.

Picture this: an attacker grabs an authentication cookie that a client uses with a certain server (maybe through a network intrusion πŸ™ˆ). The server bound that cookie to the client's Token Binding ID specifically to stop misuse. If the attacker got hold of the client's private key, they could open a TLS connection with the server, craft a Sec-Token-Binding header field that matches the binding in the cookie, and successfully authenticate as the client. Boom, they're in the client's data on the server. The Token Binding protocol didn't successfully bind the cookie to the client in that case 😭.

Integrity matters too! Likewise, we need integrity protection of the Sec-Token-Binding header field. A client should not be tricked into sending to a server a Sec-Token-Binding header field that contains Token Bindings signed with any Token Binding keys that the client does not control 🚫.

Now let's talk about the EKM, because this one is sneaky πŸ•΅οΈβ€β™€οΈ. Consider an attacker A that somehow has knowledge of the Exported Keying Material (EKM) for a TLS connection between a client C and a server S. (While that is somewhat unlikely, it's also not entirely out of the question, since the client might not treat the EKM as a secret. After all, a pre-image-resistant hash function has been applied to the TLS master secret, making it impossible for someone knowing the EKM to recover the TLS master secret. Such considerations might lead some clients to not treat the EKM as a secret.) Anyway, such an attacker A could craft a Sec-Token-Binding header field with A's key pair over C's EKM. If the attacker could then trick C into sending that header field to S, it would look to S like C controls a certain key pair, when in fact it doesn't (the attacker A controls the key pair) πŸ‘€.

If A already has a relationship with S (e.g., A has an account on S), it now appears to the server S as if A is connecting to it, even though it's really C 😳. (If the server S doesn't simply use Token Binding IDs to identify clients but also uses bound authentication cookies, then A would also have to trick C into sending one of A's cookies to S. That's doable through a variety of means, like inserting cookies through JavaScript APIs or setting cookies through related-domain attacks, etc.) In other words, in this scenario, A can trick C into logging into A's account on S. That could lead to a loss of privacy for C, since A presumably has some other way to also access the account and can thus indirectly observe C's behavior (for example, if S has a feature that lets account holders see their activity history on S) πŸ™ƒ.

So, therefore, we need to protect the integrity of the Sec-Token-Binding header field πŸ›‘οΈ. One eTLD+1 should not be able to set the Sec-Token-Binding header field (through a Document Object Model (DOM) API [W3C.REC-DOM-Level-3-Core-20040407] or otherwise) that the User Agent uses with another eTLD+1. Using the Sec- header field prefix helps meet this requirement by marking the header field name as a "forbidden header name"; see [fetch-spec]. Main character energy for the prefix, honestly πŸ’…βœ¨.


7.3. Securing Federated Sign-On Protocols

As explained above, in a federated sign-on scenario, a client will prove possession of two different Token Binding private keys to a Token Provider πŸ”‘πŸ”‘. One private key corresponds to the "provided" Token Binding ID (which the client normally uses with the Token Provider), and the other is the Token Binding private key corresponding to the "referred" Token Binding ID (which the client normally uses with the Token Consumer). The Token Provider is expected to issue a token that is bound to the Referred Token Binding ID πŸŽ€.

Both proofs (the one for the provided Token Binding private key and the one for the referred Token Binding private key) are necessary. To show this, let's walk through a scenario 🧩:

  • The client has an authentication token with the Token Provider that is bound to the client's Token Binding ID used with that Token Provider.
  • The client wants to establish a secure (i.e., free of men-in-the-middle) authenticated session with the Token Consumer but hasn't done so yet (in other words, we're about to run the federated sign-on protocol).
  • A man-in-the-middle is allowed to intercept the connection between the client and the Token Consumer, or between the client and the Token Provider (or both) πŸ‘Ή.

The goal is to detect the presence of the man-in-the-middle in these scenarios πŸ•΅οΈ.

First, consider a man-in-the-middle between the client and the Token Provider. Recall that we assume the client possesses a bound authentication token (e.g., cookie) for the Token Provider. The man-in-the-middle can intercept and modify any message sent by the client to the Token Provider, and any message sent by the Token Provider to the client. (This means, among other things, that the man-in-the-middle controls the JavaScript running at the client in the origin of the Token Provider.) It is not, however, in possession of the client's Token Binding private key. Therefore, it can choose to either (1) replace the Token Binding ID in requests from the client to the Token Provider and create a Sec-Token-Binding header field that matches the TLS connection between the man-in-the-middle and the Token Provider, or (2) leave the Sec-Token-Binding header field unchanged. If it chooses the latter, the signature in the Token Binding message (created by the original client on the EKM for the connection between the client and the man-in-the-middle) won't match a signature on the EKM between the man-in-the-middle and the Token Provider. If it chooses the former (and creates its own signature, using its own Token Binding private key, over the EKM for the connection between itself, the man-in-the-middle, and the Token Provider), then the Token Binding message will match the connection between the man-in-the-middle and the Token Provider, but the Token Binding ID in the message won't match the Token Binding ID that the client's authentication token is bound to. Either way, the man-in-the-middle is detected by the Token Provider 🚨, but only if the proof of possession of the provided Token Binding private key is required in the protocol (as is done above).

Next, consider the presence of a man-in-the-middle between the client and the Token Consumer. That man-in-the-middle can intercept and modify any message sent by the client to the Token Consumer, and any message sent by the Token Consumer to the client. The Token Consumer is the party that redirects the client to the Token Provider. In this case, the man-in-the-middle controls the redirect URL and can tamper with any redirect URL issued by the Token Consumer (as well as with any JavaScript running in the origin of the Token Consumer). The goal of the man-in-the-middle is to trick the Token Provider into issuing a token bound to its Token Binding ID and not to the Token Binding ID of the legitimate client 😈. To thwart this goal, the client's Referred Token Binding ID must be communicated to the Token Provider in a manner that can't be affected by the man-in-the-middle (who, as mentioned above, can modify redirect URLs and JavaScript at the client). Including the referred TokenBinding structure in the Sec-Token-Binding header field (as opposed to, say, including the Referred Token Binding ID in an application-level message as part of the redirect URL) is one way to assure that the man-in-the-middle between the client and the Token Consumer cannot affect the communication of the Referred Token Binding ID to the Token Provider πŸ™Œ.

So, the Sec-Token-Binding header field in the federated sign-on use case contains both a proof of possession of the provided Token Binding key and a proof of possession of the referred Token Binding key 🧁.

Note that the presence of Token Binding does not relieve the Token Provider and Token Consumer from performing various checks to ensure the security of clients during the use of federated sign-on protocols. These include the following:

  • The Token Provider should not issue tokens to Token Consumers that have been shown to act maliciously. To help with this, the federation protocol should identify the Token Consumer to the Token Provider (e.g., through OAuth client IDs or similar mechanisms), and the Token Provider should ensure that tokens are indeed issued to the Token Consumer identified in the token request (e.g., by verifying that the redirect URI is associated with the OAuth client ID) πŸ”.
  • The Token Consumer should verify that the tokens were issued for it and not for some other Token Consumer. To help with this, the federation protocol should include an audience parameter in the token response or apply equivalent mechanisms (the implicit OAuth flow requires Token Consumers to identify themselves when they exchange OAuth authorization codes for OAuth refresh tokens, leaving it up to the Token Provider to verify that the OAuth authorization was delivered to the correct Token Consumer) πŸ’œ.

8. Privacy Considerations πŸ¦‹

8.1. Scoping of Token Binding Key Pairs

Clients use different Token Binding key pairs for different servers, so Token Binding doesn't become a tracking tool across different servers πŸ‘€πŸ›‘. However, the scoping of the Token Binding key pairs to servers varies according to the scoping rules of the application protocol (Section 4.1 of [RFC8471]).

In the case of HTTP cookies, servers may use Token Binding to secure their cookies πŸͺ. These cookies can be attached to any subdomain of effective top-level domains (eTLDs), so clients therefore should use the same Token Binding key pair across such subdomains. This will ensure that any server capable of receiving the cookie will see the same Token Binding ID from the client and thus be able to verify the Token Binding of the cookie. See Section 2.1 above πŸ”—.

If the client application isn't a web browser, it may have additional knowledge about the relationship between different servers. For example, the client application might be aware that two servers play the roles of Relying Party and Identity Provider, respectively, in a federated sign-on protocol and that they therefore share the identity of the user πŸ§‘β€πŸ€β€πŸ§‘. In such cases, it is permissible to use different Token Binding key-pair scoping rules, such as using the same Token Binding key pair for both the Relying Party and the Identity Provider. Absent such special knowledge, conservative key-pair scoping rules should be used, assuring that clients use different Token Binding key pairs with different servers 🌸.

8.2. Lifetime of Token Binding Key Pairs πŸ—οΈ

okay so Token Binding key pairs don't expire. ever. πŸ’€ which means a server could use one to track you for ages, basically like a super long-lived cookie πŸͺ. so HTTPS clients like web User Agents SHOULD give people a UI for throwing out Token Binding key pairs, kind of like the delete-cookies buttons 🧹✨

and if a User Agent has a private browsing mode where it promises your browsing state (cookies and stuff) gets tossed after the session, the User Agent MUST also toss the Token Binding key pairs from that mode once the session is over. 🫢 no exceptions bestie. generally speaking, people should have the same amount of control over key pair lifetimes as they do over cookies or any other tracking thing. main character privacy energy πŸ¦‹

8.3. Correlation πŸ•ΈοΈ

so an application's endpoints that get Token Binding IDs for TLS connections that aren't their own end up learning stuff about the app's other TLS connections πŸ‘€. (here "an application" means client-side and server-side pieces talking over HTTPS, where the client side might be a web browser, a native app, or both πŸ’…) those other Token Binding IDs can act like correlation handles for the other endpoints. if the receiving endpoints already know about those other connections, then nothing new is exposed. like, if in a redirect-based federation protocol the Identity Provider and Relying Party already have each other's URLs, then also having the Token Binding IDs for those connections doesn't add any correlation info πŸ™Œ. but if they don't already know, then handing over the other Token Binding IDs exposes extra info that can be used to correlate the endpoints 😭. in those cases, a privacy analysis of the enabled correlations and their privacy impacts SHOULD be done as part of the application design decisions about how, and whether, to use Token Binding πŸŽ€

also, Token Binding implementations MUST take care to only reveal Token Binding IDs to other endpoints if the application associated with a Token Binding ID signals them to do so; see Section 6 ("Implementation Considerations") πŸ”’

finally, be careful that unrelated applications don't get info about each other's Token Bindings πŸ™ˆ. for example, a Token Binding implementation shared between multiple applications on one system SHOULD stop unrelated apps from getting each other's Token Binding info. this can be done with stuff like application isolation and key segregation, depending on what the system can do 🧚

  1. IANA Considerations πŸ“‹

here's the Internet Assigned Numbers Authority (IANA) "Permanent Message Header Field Names" registration info per [RFC3864] πŸ’–

   Header Field name:           Sec-Token-Binding
   Protocol:                    HTTP
   Status:                      standard
   Reference:                   This document

   Header Field name:           Include-Referred-Token-Binding-ID
   Protocol:                    HTTP
   Status:                      standard
   Reference:                   This document
  1. References πŸ“š

10.1. Normative References πŸ’…

[PSL]      Mozilla, "Public Suffix List",
           <https://publicsuffix.org/>.

[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>.

[RFC2818]  Rescorla, E., "HTTP Over TLS", RFC 2818,
           DOI 10.17487/RFC2818, May 2000,
           <https://www.rfc-editor.org/info/rfc2818>.

[RFC3864]  Klyne, G., Nottingham, M., and J. Mogul, "Registration
           Procedures for Message Header Fields", BCP 90, RFC 3864,
           DOI 10.17487/RFC3864, September 2004,
           <https://www.rfc-editor.org/info/rfc3864>.

[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>.

[RFC5246]  Dierks, T. and E. Rescorla, "The Transport Layer Security
           (TLS) Protocol Version 1.2", RFC 5246,
           DOI 10.17487/RFC5246, August 2008,
           <https://www.rfc-editor.org/info/rfc5246>.

[RFC5705]  Rescorla, E., "Keying Material Exporters for Transport
           Layer Security (TLS)", RFC 5705, DOI 10.17487/RFC5705,
           March 2010, <https://www.rfc-editor.org/info/rfc5705>.

[RFC6265]  Barth, A., "HTTP State Management Mechanism", RFC 6265,
           DOI 10.17487/RFC6265, April 2011,
           <https://www.rfc-editor.org/info/rfc6265>.

[RFC7230]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
           Protocol (HTTP/1.1): Message Syntax and Routing",
           RFC 7230, DOI 10.17487/RFC7230, June 2014,
           <https://www.rfc-editor.org/info/rfc7230>.

[RFC7231]  Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
           Protocol (HTTP/1.1): Semantics and Content", RFC 7231,
           DOI 10.17487/RFC7231, June 2014,
           <https://www.rfc-editor.org/info/rfc7231>.

[RFC7541]  Peon, R. and H. Ruellan, "HPACK: Header Compression for
           HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015,
           <https://www.rfc-editor.org/info/rfc7541>.

[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>.

[RFC8471]  Popov, A., Ed., Nystroem, M., Balfanz, D., and J. Hodges,
           "The Token Binding Protocol Version 1.0", RFC 8471,
           DOI 10.17487/RFC8471, October 2018,
           <https://www.rfc-editor.org/info/rfc8471>.

[RFC8472]  Popov, A., Ed., Nystroem, M., and D. Balfanz, "Transport
           Layer Security (TLS) Extension for Token Binding Protocol
           Negotiation", RFC 8472, DOI 10.17487/RFC8472, October
           2018, <https://www.rfc-editor.org/info/rfc8472>.

10.2. Informative References 🧠

[fetch-spec]
           WhatWG, "Fetch", Living Standard,
           <https://fetch.spec.whatwg.org/>.

[OASIS.saml-core-2.0-os]
           Cantor, S., Kemp, J., Philpott, R., and E. Maler,
           "Assertions and Protocols for the OASIS Security Assertion
           Markup Language (SAML) V2.0", OASIS Standard
           saml-core-2.0-os, March 2005, <http://docs.oasis-open.org/
           security/saml/v2.0/saml-core-2.0-os.pdf>.

[OASIS.saml-prof-2.0-os]
           Hughes, J., Ed., Cantor, S., Ed., Hodges, J., Ed., Hirsch,
           F., Ed., Mishra, P., Ed., Philpott, R., Ed., and E. Maler,
           Ed., "Profiles for the OASIS Security Assertion Markup
           Language (SAML) V2.0", OASIS Standard
           OASIS.saml-profiles-2.0-os, March 2005,
           <http://docs.oasis-open.org/security/
           saml/v2.0/saml-profiles-2.0-os.pdf>.

[OpenID.Core]
           Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and
           C. Mortimore, "OpenID Connect Core 1.0 incorporating
           errata set 1", November 2014,
           <http://openid.net/specs/openid-connect-core-1_0.html>.

[RFC6749]  Hardt, D., Ed., "The OAuth 2.0 Authorization Framework",
           RFC 6749, DOI 10.17487/RFC6749, October 2012,
           <https://www.rfc-editor.org/info/rfc6749>.

[RFC7540]  Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext
           Transfer Protocol Version 2 (HTTP/2)", RFC 7540,
           DOI 10.17487/RFC7540, May 2015,
           <https://www.rfc-editor.org/info/rfc7540>.

[TOKENBIND-TLS13]
           Harper, N., "Token Binding for Transport Layer Security
           (TLS) Version 1.3 Connections", Work in Progress,
           draft-ietf-tokbind-tls13-01, May 2018.

[W3C.REC-DOM-Level-3-Core-20040407]
           Le Hors, A., Ed., Le Hegaret, P., Ed., Wood, L., Ed.,
           Nicol, G., Ed., Robie, J., Ed., Champion, M., Ed., and S.
           Byrne, Ed., "Document Object Model (DOM) Level 3 Core
           Specification", World Wide Web Consortium Recommendation
           REC-DOM-Level-3-Core-20040407, April 2004,
           <https://www.w3.org/TR/2004/
           REC-DOM-Level-3-Core-20040407>.

Acknowledgements 🫢

this doc includes comments and suggestions from Eric Rescorla, Gabriel Montenegro, Martin Thomson, Vinod Anupam, Anthony Nadalin, Michael B. Jones, Bill Cox, Brian Campbell, and others πŸ’œ

it was produced under the chairmanship of John Bradley and Leif Johansson. the area directors were Eric Rescorla, Kathleen Moriarty, and Stephen Farrell ✨

Authors' Addresses 🧚

  • Andrei Popov, Microsoft Corp., United States of America. Email: andreipo@microsoft.com
  • Magnus Nystroem, Microsoft Corp., United States of America. Email: mnystrom@microsoft.com
  • Dirk Balfanz (editor), Google Inc., United States of America. Email: balfanz@google.com
  • Nick Harper, Google Inc., United States of America. Email: nharper@google.com
  • Jeff Hodges, Kings Mountain Systems, United States of America. Email: Jeff.Hodges@KingsMountain.com
πŸ“¦ where this page comes from