Upgrade OAuth 2.0 security with client certificate bound access tokens

OAuth 2.0 received its most significant security upgrade in its 7 year history, thanks to a new extension spec being developed at the OAuth WG. The simplicity of the bearer token made OAuth 2.0 the success that it is today, but is also its major weakness: whoever possesses the token is able to access the resource that it protects. Attackers aim to exploit just that -- by trying to phish or steal access tokens. Once they have them, the original user is impersonated.

The new mutual TLS extension fixes the bearer weakness with an elegant approach: if the OAuth client submits a X.509 certificate during the TLS exchange at the token endpoint, the issued access token is automatically bound to the certificate.

The binding is expressed as a "cnf.x5t#S256" claim associated with the token, representing the client certificate's SHA-256 thumbprint:

 "iss" : "https://c2id.com",
 "sub" : "[email protected]",
 "exp" : 1493726400,
 "scp" : [ "openid", "read", "write" ],
 "cnf" : { "x5t#S256" : "bwcK0esc3ACC3DB2Y5_lESsXE8o9ltc05O89jdN-dg2" }

When the client accesses a protected resource with the bound token, such as the UserInfo endpoint of an OpenID provider, the client X.509 certificate must again be submitted with the HTTPS request. The resource server will compare the expected hash with that of the received certificate, and if they match, the request can proceed. If they don't match, or no certificate was submitted, an invalid token error is returned.

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token" error_description="Missing / invalid client X.509 certificate for x5t#S256 bound access token"

Client certificate bound tokens are great security enhancement to OAuth 2.0. Even if an attacker succeeds in stealing a token, e.g. from a compromised client app store, that won't be enough to access the resource server. The private key for the client certificate must also be possessed, and that key may be safely locked in a secure element or HSM.

The mutual TLS spec has some neat features you should be aware of:

  • It also works with self-signed client certificates, so there's no need to deploy heavy PKIX along your OAuth 2.0 / OpenID Connect servers and applications.

  • Even if you choose to setup a CA for issuing the client certificates, the resource servers don't need to validate the full certificate chain, as only the client certificate's hash must be computed to validate the token binding.

  • The client certificate can also serve as a client authentication method at the token endpoint (instead of HTTP basic auth or the JWT assertion methods).

  • Public OAuth 2.0 clients, e.g. on mobile devices, can also use a client X.509 certificate to received bound tokens.

  • It works with all OAuth 2.0 grant types, or at least that's how we implemented it in the Connect2id server.

We're pleased to announce you can now use the Connect2id server to issue client certificate bound access tokens. Support for that is available in the latest 6.13 release.

Here are two guides to get you started:

Other new features in v6.13:

See the release notes below for additional information.


To download a ZIP package of Connect2id server 6.13:


(SHA-256: 3bcaadb0316d1cdb85f075ee8cf2acef58d83be82e7408e0ee78963bd33e3912)

As WAR package only:


(SHA-256: ed79c70ebacd283a5ebdb4e317a15825710a2a5762231b3e6c1bc75dce12a69f)


Get in touch with Connect2id support.

Release notes

6.13 (2017-08-17)


  • Adds support for issuing and inspecting client X.509 certificate bound access tokens. See Mutual TLS Profile for OAuth 2.0 (draft-ietf-oauth-mtls-03).

  • Adds support for the Financial Services – Financial API - Part 2: Read and Write API Security Profile (implementers' draft from 2017-07-17).


  • /WEB-INF/authzStore.properties

    • authzStore.refreshToken.alwaysUpdate -- New configuration setting, if
      "true" causes the refresh token to be updated on each authorisation update and on each refresh token use. Defaults to "false" (no update). See The OAuth 2.0 Authorization Framework (RFC 6749), section 6.
  • /WEB-INF/oidcProvider.properties

    • op.idToken.includeStateHash --- New configuration setting, if "true" causes a state hash (s_hash) claim to be included in issued ID tokens. The state hash claim is specified in Financial Services – Financial API - Part 2: Read and Write API Security Profile, section 5.1.
  • /WEB-INF/web.xml

    • Adds a startup listener (SystemPropertyLoader) for loading additional Java system properties from a local file if the Java system property named "systemPropertiesFile" is set. May be used in cloud, virtualised and container deployments to pass selected Connect2id server configuration properties as an external text file.

    • Adds a startup listener (SystemPropertyNameDotRestore) for restoring Java system property names where dot characters "." have been replaced with underscore "_" characters. May be used in AWS Elastic Beanstalk deployments to pass selected Connect2id server configuration properties as environment variables where underscore characters are not allowed in the environment variable name (and cannot be escaped).

  • /WEB-INF/infinispan-mysql-{redis}.xml

    • Changes "dataSourceClassName" to "org.mariadb.jdbc.MariaDbDataSource" (MariaDB driver library included in the c2id.war, compatible with MySQL).

    • Changes default "dataSource.url" to "jdbc:mariadb:...".


  • /.well-known/openid-configuration

    • Includes the "mutual_tls_sender_constrained_access_tokens" parameter in the advertised OpenID provider metadata.
  • /clients

    • OAuth 2.0 clients registered for public key bound TLS client authentication (pub_key_tls_client_auth) will also be implicitly registered to receive access tokens bound to the client X.509 certificate (mutual_tls_sender_constrained_access_tokens=true). Explicit registration to receive client certificate bound access tokens and to have that setting enforced by requiring a client certificate to be presented at the token endpoint is not supported at present for public OAuth 2.0 clients or confidential OAuth 2.0 clients having another authentication method.
  • /token

    • Confidential as well as public OAuth 2.0 clients which submit a client X.509 certificate during the TLS handshake will be issued with an access token bound to the certificate using its SHA-256 thumbprint (as cnf.x5t#S256 token claim). Applies to self-contained (JWT) as well as identifier (key) based access tokens.
  • /token/introspect

    • Adds support for inspecting client X.509 certificate bound access tokens (self-contained and identifier-based). The certificate binding, if present for the token, is indicated by the cnf.x5t#S256 claim.
  • /userinfo

    • Adds support for handling client X.509 certificate bound access tokens. OAuth 2.0 clients which submit a bound access token without the matching client X.509 certificate will have their UserInfo request denied (HTTP 401 Unauthorized) with an "invalid_token" error. See The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750), section 3.

Resolved Issues

  • Adds refresh token decoding exception logging at debug level (issue authz-store/142).

Dependency changes

  • Upgrades to com.nimbusds:oauth2-oidc-sdk:5.35
  • Upgrades to com.nimbusds:nimbus-jose-jwt:4.41.1
  • Upgrades to com.nimbusds:oauth2-authz-store:5.17