Access Management 7.3.2

Certificate-bound proof-of-possession

AM supports associating an X.509 certificate with an access token to support proof-of-possession interactions, as per version 12 of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

This ensures that only the client in possession of the private key corresponding to the certificate can use the bearer token to access protected resources.

Since the resource server validates the hash contained in the access token as proof-of-possession against the client’s certificate, clients must use the certificate used to request the bearer token when accessing the protected resources. Moreover, this implies that access tokens are invalidated when clients update their certificates.

OAuth 2.0 Certificate-Bound Proof-of-Possession Flow
Figure 1. OAuth 2.0 Certificate-Bound Proof-of-Possession Flow
Certificate-Bound Proof-of-Possession Flow Explained
  1. The client, communicating over TLS, requests an access token using an OAuth 2.0 grant flow.

    The implicit grant flow does not support certificate-bound proof-of-possession. For more information, see the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

  2. The authorization server returns the access token to the client with the client’s certificate hash embedded:

    • If the authorization server is configured for server-side OAuth 2.0, the authorization server stores the certificate hash with the access token in the CTS token store and provides the client with the access token ID.

    • If the authorization server is configured for client-side OAuth 2.0, the access token is a JWT that contains the certificate hash embedded in it.

    The hash of the client’s certificate is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

  3. The client, communicating over mTLS, requests access to the protected resources from the resource server.

  4. The resource server validates the client’s certificate with the certificate hash contained in the access token:

    • If the authorization server is configured for server-side OAuth 2.0, the resource server calls the OAuth 2.0 introspect endpoint with the access token to recover the cnf claim that contains the certificate’s hash.

    • If the authorization server is configured for client-side OAuth 2.0, the resource server recovers the cnf claim that contains the certificate’s hash from the access token JWT.

  5. The resource server allows access to the protected resources.

To configure your environment for certificate-bound tokens, see the following sections:

Obtain certificate-bound tokens when mutual TLS authentication is configured

Clients can authenticate to the OAuth 2.0 endpoints by presenting X.509 self-signed or CA-signed certificates as per version 12 of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

Depending on the type of client, AM performs the following actions:

  • Confidential clients. When clients present a certificate as the authentication method while making a call to the token endpoint, AM authenticates the client and AM binds the certificate to the access token.

  • Public clients. When clients present a certificate while making a call to the token endpoint, AM ignores the certificate for authentication purposes and binds the certificate to the access token.

Perform the steps in the following procedure to obtain a certificate-bound access token when a client authenticates using mutual TLS:

  1. Ensure your environment enforces TLS between the authorization server and the clients, and between the resource server and the clients.

    Self-signed and CA-signed certificates are supported.

    You must configure the container where AM runs to request and accept client certificates.

  2. Configure AM as an OAuth 2.0 authorization server using the following information:

    • You must enable the Support TLS Certificate-Bound Access Tokens switch (Realms > Realm Name > Services > OAuth2 Provider > Advanced).

      This property specifies whether AM should bind certificates to access tokens when clients authenticate using TLS client certificates.

    • If TLS is being terminated at a reverse proxy or load balancer, you must configure the Trusted TLS Client Certificate Header property (Realms > Realm Name > Services > OAuth2 Provider > Advanced) to hold the name of the HTTP header that will provide AM with the client certificate.

      For more information, see Providing Client Certificates to AM.

  3. Register an OAuth 2.0 client in AM.

    The following configuration will be used in the examples of this procedure:

    • Client ID: myClient

    • Scopes: write

    • Grant Types: Client Credentials

    • You must enable the Use Certificate-Bound Access Tokens switch (Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Signing and Encryption).

      This switch specifies whether AM should bind certificates to access tokens for this client when the client authenticates to the token endpoint using a TLS client certificate. When disabled, AM does not bind certificates to access tokens issued to the client even if the client presents a TLS client certificate.

  4. Configure the client for mutual TLS authentication.

    For more information, see Mutual TLS.

  5. The client makes a call to the token endpoint to request an access token, and includes its client certificate in the call:

    $ curl \
    --request POST \
    --cacert AMServer.cer \
    --data "client_id=myClient" \
    --data "grant_type=client_credentials" \
    --data "scope=write" \
    --data "response_type=token" \
    --cert myClientCertificate.pem \
    --key myClientCertificate.key.pem \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    The authorization server returns the access token:

    • If server-side OAuth 2.0 tokens are enabled, the response will include an access token ID in the access_token property, which identifies the access token data stored on the server. For example:

      {
          "access_token":"f08f1fcf-3ecb-4120-820d-fb71e3f51c04",
          "scope":"profile",
          "token_type":"Bearer",
          "expires_in":3599
      }
    • If client-side OAuth 2.0 tokens are enabled, the response will be a JWT in the access_token, which has the JWK embedded within. The following example has shortened the access token for display purposes:

      {
          "access_token": "eyJ0eXAiOiJKV1QiLCHi51zbE3t…​zc2NjI3NDgsInNjb3zUOCVKCX0Se0",
          "scope": "profile",
          "token_type": "Bearer",
          "expires_in": 3599
      }
  6. The client requests access to the protected resources.

    The resource server validates the hash contained in the access token against the certificate the client presents as part of the TLS handshake.

    The hash contained in the access token is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

    If server-side OAuth 2.0 tokens are enabled, the resource server can make a POST request to the introspect endpoint to acquire the certificate’s hash:

    $ curl \
    --request POST \
    --header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \
    --data "token=f08f1fcf-3ecb-4120-820d-fb71e3f51c04" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
    {
       "active":true,
       "scope":"write",
       "client_id":"myClient",
       "user_id":"myClient",
       "username":"myClient",
       "token_type":"Bearer",
       "exp":1547079953,
       "sub":"(age!myClient)",
       "subname":"myClient"
       "iss":"https://openam.example.com:8443/openam/oauth2",
       "cnf":{
          "x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
       }
    }

    If client-side OAuth 2.0 tokens are enabled, the resource server can decode the JWT to access the cnf key in the JWT’s payload. For example:

    {
      "sub": "myClient",
      "cts": "OAUTH2_STATELESS_GRANT",
      ....
      "cnf": {
         "x5t#S256": "m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
      },
      "exp": 1547083590,
      "iat": 1547079990,
      "expires_in": 3600,
      "jti": "sLzkRiayAQKsrXN0Gu_vwFog3Rs"
    }

Obtain certificate-bound tokens without configuring mutual TLS authentication

Clients can obtain a certificate-bound access token when making a call to the OAuth 2.0 endpoints as long as they provide an X.509 client certificate in one of the following ways:

  • Presenting a self-signed or CA-signed certificate as part of the TLS handshake with AM.

    AM authenticates the clients using the specified credentials (for example, client ID and secret) and binds the certificate to the access token.

    Your environment must enforce TLS between the authorization server and the clients, and between the resource server and the clients.

    You must also configure the container where AM runs to request and accept client certificates.

  • Providing a hash of the self-signed or CA-signed certificate in the cnf_key parameter as part of the call to the OAuth 2.0 endpoint.

    This method uses capabilities already implemented in AM that are not part of the OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens internet-draft.

    Use this option only if the client cannot authenticate its TLS connection to AM.

Perform the steps in the following procedure to obtain a certificate-bound access token when clients are not authenticating with mutual TLS:

  1. Configure AM as an OAuth 2.0 authorization server using the following information:

    • You must enable the Support TLS Certificate-Bound Access Tokens switch (Realms > Realm Name > Services > OAuth2 Provider > Advanced).

      This property specifies whether AM should bind certificates to access tokens when clients authenticate using TLS client certificates.

    • If not using the cnf_key, and if TLS is being terminated at a reverse proxy or load balancer, you must configure the Trusted TLS Client Certificate Header property (Realms > Realm Name > Services > OAuth2 Provider > Advanced) to hold the name of the HTTP header that will provide AM with the client certificate.

      For more information, see Provide client certificates to AM.

  2. Register a client in AM.

    The following configuration will be used in the examples of this procedure:

    • Client ID: myClient

    • Scopes: write

    • Grant Types: Client Credentials

    • or confidential clients, configure a secret. For example:

      • Client Secret: forgerock

    • You must enable the Use Certificate-Bound Access Tokens switch (Realms > Realm Name > Applications > OAuth 2.0 > Clients > Client ID > Signing and Encryption).

      This switch specifies whether AM should bind certificates to access tokens for this client when the client authenticates to the token endpoint using a TLS client certificate. When disabled, AM does not bind certificates to access tokens issued to the client even if the client presents a TLS client certificate.

  3. The client makes a call to the token endpoint to request an access token, and includes its client certificate in the call:

    $ curl \
    --request POST \
    --cacert AMServer.cer \
    --data "client_id=myClient" \
    --data "client_secret=forgerock" \
    --data "grant_type=client_credentials" \
    --data "scope=write" \
    --data "response_type=token" \
    --cert myClientCertificate.pem \
    --key myClientCertificate.key.pem \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    To use the cnf_key parameter, the client must perform the following additional steps:

    • Calculate the SHA-256 hash of the DER-encoding of the full X.509 client certificate and base64URL-encode it. For example:

      m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0
    • Store the certificate’s hash in JSON format, as follows:

      {"x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"}
    • Base64-encode the JSON. For example:

      eyJ4NXQjUzI1NiI6Im04VWNXQlNQTnRhS04xOVRkUjh6VUh2V1dPU0NTWDluc2E1dlU2ZnNjZDAifQ==
    • Make a call to the token endpoint to request an access token, including the cnf_key parameter with the certificate hash. Note that the client certificate is not included in any other way:

      $ curl \
      --request POST \
      --data "grant_type=client_credentials"\
      --data "client_id=myClient" \
      --data "client_secret=forgerock" \
      --data "cnf_key=eyJ4NXQjUzI1NiI6Im04
                      VWNXQlNQTnRhS04xOVRk
                      Ujh6VUh2V1dPU0NTWDlu
                      c2E1dlU2ZnNjZDAifQ==" \
      "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token"

    The authorization server returns the access token:

    • If server-side OAuth 2.0 tokens are enabled, the response will include an access token ID in the access_token property, which identifies the access token data stored on the server. For example:

    {
        "access_token":"f08f1fcf-3ecb-4120-820d-fb71e3f51c04",
        "scope":"profile",
        "token_type":"Bearer",
        "expires_in":3599
    }
    • If client-side OAuth 2.0 tokens are enabled, the response will be a JSON web token in the access_token, which has the certificate hash embedded within. The following example has shortened the access token for display purposes:

    {
        "access_token": "eyJ0eXAiOiJKV1QiLCHi51zbE3t…​zc2NjI3NDgsInNjb3zUOCVKCX0Se0",
        "scope": "profile",
        "token_type": "Bearer",
        "expires_in": 3599
    }
  4. The client requests access to the protected resources from the resource server and the resource server validates the hash contained in the access token against the certificate the client presents as part of the TLS handshake.

    The hash contained in the access token is stored in the cnf confirmation key of the type x5t#S256, which contains the base64URL-encoded SHA-256 hash of the DER-encoding of the full X.509 certificate.

    If server-side OAuth 2.0 tokens are enabled, the resource server can make a POST request to the introspect endpoint to acquire the certificate’s hash:

    $ curl \
    --request POST \
    --header "Authorization: Basic bXlDbGllbnQ6Zm9yZ2Vyb2Nr" \
    --data "token=f08f1fcf-3ecb-4120-820d-fb71e3f51c04" \
    "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect"
    {
       "active":true,
       "scope":"write",
       "client_id":"myClient",
       "user_id":"myClient",
       "username":"myClient",
       "token_type":"Bearer",
       "exp":1547079953,
       "sub":"(age!myClient)",
       "subname":"myClient"
       "iss":"https://openam.example.com:8443/openam/oauth2",
       "cnf":{
          "x5t#S256":"m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
       }
    }

    If client-side OAuth 2.0 tokens are enabled, the resource server can decode the JWT to access the cnf key in the JWT’s payload. For example:

    {
      "sub": "myClient",
      "cts": "OAUTH2_STATELESS_GRANT",
      ....
      "cnf": {
        "x5t#S256": "m8UcWBSPNtaKN19TdR8zUHvWWOSCSX9nsa5vU6fscd0"
      },
      "exp": 1547083590,
      "iat": 1547079990,
      "expires_in": 3600,
      "jti": "sLzkRiayAQKsrXN0Gu_vwFog3Rs"
    }