Token binding explained

The bearer property of tokens blessed OAuth 2.0 with simplicity. But it also exposed a weak point, for a token should only work for the client it was issued to, else we end up with a major security disaster. Token binding is designed to fix the bearer weakness, rendering the token unusable in a TLS (HTTPS) connection established by a client other than the legitimate one.

1. The bearer property as mixed blessing

Developers love simplicity and OAuth 2.0, the standard framework for token-based security, owes much of its success and widespread adoption to the bearer access tokens. Bearer means that whoever holds the token is assumed to have the right to access the resource (web API) it was minted for. Developers are freed from dealing with cryptography in client application code; there's no need to sign the token and selected request parameters, as in version 1.0 of OAuth.

Example passing of a bearer token in a HTTP request:

GET /resource HTTP/1.1
Host: myapi.example.com
Authorization: Bearer zoocuequie8Ichee7oeGeeth7chaisha

The bearer property of tokens makes it easier for clients to construct requests to resource servers, but also potentially to change hands and impersonate the user. This is a major security risk. Basic OAuth 2.0 addresses it by requiring safe passing (via TLS (HTTPS)) of the token from authorisation server to client and from client to protected resource, as well as safe storage on the client side. If the token does leak - a short, limited lifespan is recommended to mitigate unauthorised replay.

But those measures are not convincing enough for applications which deal with high-value resources, as in open banking. Those need an extra layer of security on top of the bearer token, on which addresses the risk of theft and impersonation more effectively.

2. Binding the token to a client private key that cannot be extracted

An effective solution is to bind the token to something the OAuth 2.0 client possesses and that cannot be easily extracted by a malicious party.

The standard candidate for this task is public / private key cryptography, ideally backed by hardware-based storage, such as a Hardware Security Module (HSM) or a Trusted Platform Module (TPM):

  • The private key of the client is generated and stored in hardware, protected against extraction, which lets us strongly identify the client with the key.

  • The issued token is bound to the private key of the client. The binding is secured cryptographically, by means of a digital signature. The binding verification involves checking the signature with the corresponding public key of the client.

  • Even if the client cannot afford a hardware-based key store, it's much easier to secure a single key than an entire database of tokens.

3. The token binding protocol

Are we back to the digital signatures of OAuth 1.0? Not necessarily. The logical binding binding between token and the client private key can be established in various ways, each with its own pros and cons.

In OAuth 1.0 the client signs the token (and other selected parameters) directly for each HTTP request to the resource server. This complicates the server side, as the OAuth server must sync the public keys for all clients with every participating resource server. In distributed applications with many resource servers this can turn into a heavy burden and dependency.

The token binding protocol explained here takes a different approach. Instead of signing the token directly, the digital signature is used (primarily) to prove possession of the private key.

How does essentially the token binding protocol work?

  1. It's implemented as a TLS extension (i.e. requires HTTPS).

  2. The client generates a long-lived private key for each server.

  3. The client turns the corresponding public key into a simple unique data structure called the token binding ID.

  4. For each TLS connection to the server, the client includes a token binding message which carries the token binding ID (the public key) together with a proof that the client has possession of the private key. This is proof is made by simply signing the token binding ID (the public key) together with unique data from the TLS session with the private key.

  5. The server verifies the proof (signature) and binds the issued security token to the token binding ID (the client public key). The actual binding can be implemented in various ways, e.g. by including the binding ID or its hash in the issued token.

Benefits of the token binding protocol:

  • Universal -- Can be used to secure all kinds of objects in the application layer, not just those found in OAuth 2.0, such as tokens and authorisation grants, but also OpenID Connect ID tokes or quite importantly HTTP cookies.

  • Can span multiple parties -- The protocol can work with a single client / server pair (provided binding) as well as with multiple parties (via referred binding), for example the client, OAuth 2.0 server and protected resource. There is no need to sync public keys out of band between the parties.

  • The token is also bound to the TLS connection -- The token is bound not only to the client private key, but also to the TLS connection, since the signature covers unique data from it as well.

  • Long-lived bindings -- The client can use the private key (and hence the derived token binding ID) for all TLS connections to the server.

  • Resettable -- At any one time the client can discard the private key and generate a new one for a fresh token binding ID.

Disadvantages:

  • Poor API support -- The token binding protocol is implemented as a TLS extension. Unfortunately, many popular programming languages, such as Java, have poor API support for plugging in the TLS extension logic required by the token binding protocol. Built-in support for the extension in their TLS implementation is also unlikely to appear soon.

  • Requires TLS -- The token binding protocol requires TLS, but this isn't much of an issue since the use of TLS (HTTPS) is ubiquitous today.

4. The OAuth 2.0 mutual TLS alternative

There's an alternative to token binding, called OAuth 2.0 mutual TLS, for binding access and refresh tokens to a client's X.509 certificate.

Clients can choose between PKI based and self-signed certificates. With a self-signed certificate the client must register it or its public key in JWK format with the OAuth 2.0 server in order to make token requests.

The private key used to sign the certificate can also potentially be generated and stored securely in hardware, to prevent its extraction.

Where does the client present its certificate?

  • When requesting a new token from the OAuth 2.0 server, in order to have the token bound, typically by including the certificate hash in it.

  • When accessing a protected resource with it, so the resource server can compare the hash of the received client certificate with the expected hash indicated in the token.

Benefits of client certificate bound tokens:

  • Doubles as a client authentication method -- Confidential OAuth 2.0 clients can also authenticate to the authorisation server this way.

  • Easy to implement -- Especially with self-signed certificates, which don't require a PKI to be set up and maintained. Developers can rely on stable existing support for X.509 certificates in all popular programming languages.

Disadvantages:

  • Implicit grant not covered -- Access tokens obtained through the implicit OAuth 2.0 flow cannot be bound, but this isn't much of an issue since the kind of applications that require token bound security will likely use the code flow.

5. The token binding specifications

The mechanics of token binding is developed at a working group at the IETF:

The application of token binding to OAuth 2.0 is developed in the OAuth WG and is still a work in progress:

  • OAuth 2.0 Token Binding (draft-ietf-oauth-token-binding-08) -- Specifies a complete OAuth 2.0 profile for binding tokens, grants and the associated client and authorisation server metadata.

Token binding can of course also be applied in OpenID Connect:

6. Resources for developers

Implementing token binding for a particular language / environment can be an easy job or require an ugly hack. That's because code in the application layer needs to reach into the TLS layer, and the TLS layer implementation must allow to be plugged in with the necessary extension logic for the token binding negotiation. Unfortunately, such TLS extension plugin APIs are rarely provider. This can be quite an obstacle for developers on the client side.

On the server side it can be easier to simply set up an Apache HTTPd with mod_token_binding as reverse proxy in front of the web application.

If you're working on a token binding implementation, drop us a note!

6.1 mod_token_binding for Apache HTTPd

Hans Zandbelt has developed a module for the Apache web server which handles the token binding TLS extension on the server side and passes the successfully verified provided or referred bindings as security HTTP headers to the application, which can then issue bound cookies and tokens.

7.1 Java

Brian Campbell has created a Java library for creating and processing of token binding messages, plus special Java code for getting the token binding extension logic into the OpenJDK implementation. Unfortunately, Java doesn't lacks a proper API for plugging a TLS extension, so the native solution to that is messy and JDK version dependent.

7.2 .NET

Microsoft implemented a .NET TokenBinding class as part of its next gen crypto API.


comments powered by Disqus