mTLS Integration (Optional)

Set up mutual TLS authentication for RiskOS™ API calls using client certificates to enforce two-way identity verification.

What is mTLS?

mTLS (Mutual TLS) is a security protocol where both the client and server authenticate each other using certificates, unlike regular TLS where only the server is authenticated.


How it works

Socure provides a dedicated mTLS endpoint for each environment:

EnvironmentmTLS base URL
Sandboxhttps://mtls.riskos.sandbox.socure.com
Productionhttps://mtls.riskos.socure.com
  • Transport: HTTPS with mutual TLS (mTLS)
  • Policy: Client certificate is required – connections without a valid certificate are rejected at the load balancer.
  • Supported operations: All API Reference endpoints are available through the mTLS base URL.

At this endpoint:

  • The External HTTPS Load Balancer:
    • Terminates TLS
    • Validates the client certificate against our configured trust store
  • Allows only requests presenting a valid client certificate issued from the agreed-upon client CA to reach our services.
  • Application authentication/authorization (for example, the Bearer token) still enforced on top of mTLS

📘

Account-level constraints:

  • Account-Level Identity: mTLS certificates are configured at the Account level, not per use case. All teams or applications within the same RiskOS™ account must use the same certificate bundle.
  • Product Separation: You cannot reuse mTLS certificates from Socure ID+. Because RiskOS™ is a separate account environment, a new certificate exchange specifically for RiskOS™ is required.
  • Optional Usage: mTLS is not strictly enforced for the entire account unless required by your internal policy.
    • To use mTLS: Call the mTLS base URL for your environment — https://mtls.riskos.sandbox.socure.com (Sandbox) or https://mtls.riskos.socure.com (Production).
    • To skip mTLS: Call the standard endpoint — https://riskos.sandbox.socure.com (Sandbox) or https://riskos.socure.com (Production).

Flow diagram

This diagram shows the end-to-end mTLS connection — what happens at each hop between the client, the RiskOS™ load balancer, and the RiskOS™ API server. Note that the client verifies the server certificate (step 3) before it presents its own client certificate.

sequenceDiagram
    title RiskOS™ mTLS — End-to-End Flow

    participant C as Client
    participant LB as RiskOS™ Load Balancer
    participant API as RiskOS™ API Server

    Note over C: Customer generates PKI chain:<br/>Root CA → Intermediate CA → Leaf client cert

    Note over C,LB: Before integration: customer shares<br/>CA bundle (Root + Intermediate) with Socure

    C->>LB: 1. ClientHello — TLS handshake initiated
    LB->>C: 2. Server presents its certificate
    C->>C: 3. Client verifies server certificate<br/>(public CA or configured trust anchor)
    LB->>C: 4. Server requests client certificate
    C->>LB: 5. Client sends leaf certificate
    LB->>LB: 6. Validate client cert against TrustConfig<br/>(customer CA bundle)

    alt Invalid or missing client cert
        LB--X C: TLS handshake failure
    end

    Note over C,LB: 7. Encrypted TLS session established

    C->>LB: 8. Encrypted HTTPS request
    LB->>API: 9. Plain HTTP request<br/>(TLS terminated at load balancer)
    API->>API: 10. Application auth<br/>(Bearer token / API key)
    API-->>LB: 11. HTTP response
    LB-->>C: 12. Encrypted HTTPS response

At each layer

LayerWhat happens
ClientInitiates the TLS handshake, verifies the RiskOS™ server certificate, presents the leaf certificate and private key when requested, sends the encrypted HTTPS request, and receives the encrypted HTTPS response.
RiskOS™ load balancerPresents the server certificate, requests and validates the client certificate against TrustConfig, terminates TLS, forwards plain HTTP to the backend, and re-encrypts the response over TLS back to the client.
RiskOS™ API serverEnforces Bearer token authentication on top of mTLS, then processes the request and returns the response.

Prerequisites

Make sure the following are in place:

  1. Ability to perform HTTPS requests with client certificate authentication.
  2. Required certificate assets unique to your RiskOS™ account:
    • A client certificate (client.crt).
    • Its private key (client.key).
    • The client CA / chain that issued that certificate.
  3. Share your CA bundle (Root and Intermediate public certificates) with Socure for configuration in our Trust Store. See What to send Socure for the required format.

Certificate requirements

Certificate roles

Each certificate in the chain has a distinct role. Only your CA public certificates are shared with Socure; your leaf certificate and private key stay on your side.

CertificateBasic ConstraintsExtended Key UsageSend to Socure?Customer uses at runtime?
Root CACA:TRUE (required)—Yes (public certificate only)No
Intermediate CACA:TRUE (required)—Yes (public certificate only)No
Leaf (client) certificateCA:FALSE (required)TLS Web Client Authentication (required)Optional (for testing only)Yes (client.crt and client.key)
⚠️

Do not send Socure a CSR:

Socure does not sign customer certificate requests. Generate and sign certificates on your side using your internal PKI, then share your CA public certificates (Root and Intermediate) for Trust Store configuration.

📘

Note:

Socure configures CA certificates (Root and Intermediate) in our GCP Trust Store — not individual client leaf certificates. Your leaf certificate is used only on your side when calling the mTLS endpoint. Because Socure trusts the CA rather than the leaf certificate, you can issue a new leaf certificate from the same CA without a new certificate exchange.


1. Client certificate type

  • Must be an X.509 v3 certificate suitable for TLS client authentication.
  • Must be issued by a CA that we mutually agree on and configure in our GCP TrustConfig as a trustAnchor.
  • The CA bundle must contain the chain: Intermediate CA → Root CA.
  • Key size: RSA 2048+ or ECDSA (P-256).
  • The chain must validate with openssl verify.

2. Subject / DN

Use stable identifiers that describe your application, RiskOS™ integration, environment, and organization.

Recommended CN pattern:

{application}-riskos-{environment}.{your-domain}

Examples:

  • Sandbox: onboarding-riskos-sandbox.acme-finance.com
  • Production: payments-riskos-prod.acme-finance.com

The riskos segment identifies the certificate for RiskOS™ mTLS integration. Replace acme-finance.com with your organization's domain.

Keep O and OU distinct:

  • O (Organization): Your company's legal name — for example, Acme Finance Corporation.
  • OU (Organizational Unit): The internal team that owns the integration — for example, Enterprise API Platform.

Do not use RiskOS in O or OU — those describe your organization, not Socure's product.

Socure maps certificate identity (CN / DN / serial / issuer) to your account for future reference.


How Socure configures trust on our side

You don't need to do this, but it helps you understand the behavior:

  • We configure a ServerTlsPolicy on the Target HTTPS Proxy with:
    • clientValidationMode = REJECT_INVALID

      → Any missing/invalid client certificate is rejected at TLS handshake

    • clientValidationTrustConfig pointing to a TrustConfig that contains your client CA under trustAnchors

Implication for you: If your client does not present a valid certificate signed by this CA, the TLS handshake fails before any HTTP request is received.


What to send Socure

Share a PEM file that contains your CA chain (public certificates only):

-----BEGIN CERTIFICATE-----
(Intermediate CA — CA:TRUE)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(Root CA — CA:TRUE)
-----END CERTIFICATE-----
⚠️

Never share private keys (*.key), certificate signing requests (CSRs), or leaf private keys.

Allow 3–5 business days for Trust Store configuration after submission.


Client-side configuration – general

From the client side, mTLS is simply:

  • "Use this certificate + key when calling https://mtls.riskos.socure.com"

You typically configure:

  • Client certificate file (PEM or PFX)
  • Private key file (if not bundled)
  • Trusted server CA (optional if our server certificate is from a public CA your system already trusts)

Example integrations

1. cURL

curl -v \
  --cert /path/to/client.crt \
  --key /path/to/client.key \
  --cacert /path/to/ca_root.crt \
  https://mtls.riskos.socure.com/api/evaluation
  --header 'accept: application/json' \
  --header 'content-type: application/json'
  --data '
  {
    "data": {
      "individual": {
        .....
      },
      ....
    },
    ....
  }
import requests

url = "https://mtls.riskos.socure.com/api/evaluation"
headers = {
    "accept": "application/json",
    "content-type": "application/json",
}
payload = {
    "data": {
        "individual": {
            # ...
        },
        # ...
    },
    # ...
}

response = requests.post(
    url,
    headers=headers,
    json=payload,
    cert=("/path/to/client.crt", "/path/to/client.key"),
    verify="/path/to/ca_root.crt",
)
data = response.json()

Notes:

  • --cert: Client certificate (PEM). If combined with key in PFX, use --cert client.p12:password --cert-type P12
  • --key: Client private key
  • --cacert: CA to verify our server certificate (optional if you already trust the issuing public CA)

If the certificate is missing or invalid, you see a TLS handshake error such as:

  • SSL_ERROR_HANDSHAKE_FAILURE_ALERT
  • OPENSSL_internal:KEY_VALUES_MISMATCH
  • Socket hang up

2. Python as a client

import requests

BASE_URL = "https://mtls.riskos.socure.com"

# Paths to your certificate files
CLIENT_CERT = "/path/to/client.crt"      # client certificate (PEM)
CLIENT_KEY = "/path/to/client.key"       # client private key (PEM)
CA_CERT = "/path/to/ca_root.crt"         # CA to trust our server cert (optional if system trust is enough)

def main():
    try:
        # JSON payload matching your curl example
        payload = {
            "data": {
                "individual": {
                   ....
                },
                ....
            },
           ....
        }

        headers = {
            "accept": "application/json",
            "content-type": "application/json",
        }

        response = requests.post(
            f"{BASE_URL}/api/evaluation",
            headers=headers,
            json=payload,               # sends JSON body like curl --data '<json>'
            cert=(CLIENT_CERT, CLIENT_KEY),
            verify=CA_CERT,             # same as --cacert; use True if using system trust store
            timeout=10,
        )
        print("Status:", response.status_code)
        print("Body:", response.text)
    except requests.exceptions.SSLError as e:
        print("TLS/mTLS error:", e)
    except requests.exceptions.RequestException as e:
        print("Request error:", e)

if __name__ == "__main__":
    main()

API behavior and authentication

Please note the following important points:

  • mTLS = transport-level identity, not necessarily your full application authentication
  • You must still provide a Bearer token in Authorization: Bearer YOUR_API_KEY
  • Typical pattern:
    • mTLS authenticates the calling system
    • The Bearer token authenticates the user or client app context

Error scenarios you should expect

  1. TLS handshake failure (no HTTP status code)
    • Likely causes:
      • Missing client certificate
      • Invalid chain (not signed by configured CA)
      • Expired or not yet valid certificate
    • Resolution:
      • Check your client certificate/key configuration
      • Check certificate validity dates
      • Confirm you're using the correct certificate for production vs sandbox
      • Confirm CA chain matches what you shared with us
  2. HTTP 401 / 403 / 429 from API
    • mTLS succeeded, but:
      • Bearer token is invalid or missing
      • Your IP is not whitelisted in our system
      • Your request hit the rate limit
  3. HTTP 404 / 405 / 500 responses
    • mTLS layer is OK; these are regular API-level errors (wrong path, method, or internal error)

Certificate rotation guidance

Customer responsibilities:

  • Rotate customer certificates before the not_after date
  • Notify us of the new customer CA (if your CA changes)

Socure will:

  • Update our TrustConfig / trustAnchors if your CA changes
  • Keep both old and new CAs during migration windows when needed

How to inform us: Contact our Support team at [email protected].

Lead time required: Please allow 3–5 business days for CA changes


Common error messages and causes

Errors are often reported by the client's application, browser, or server logs during the TLS handshake.

  • SSL connect error, ERR_SSL_PROTOCOL_ERROR, or handshake failure
    These indicate a fundamental failure in the TLS negotiation process, often due to configuration issues on either the client or server side.

  • CERTIFICATE_VERIFY_FAILED or SSL certificate problem
    These errors are often seen in clients like Python requests or cURL and indicate a problem with the certificate itself or the validation process.

  • UNABLE_TO_GET_ISSUER_CERT or UNABLE_TO_VERIFY_LEAF_SIGNATURE
    This happens when the server (or client) cannot build a complete, trusted chain from the presented certificate back to a known and trusted root Certificate Authority (CA).

  • The user certificate is expired or blacklisted
    The validating party has identified that the certificate's validity date is in the past, or it is present on a Certificate Revocation List (CRL).

  • Unsupported certificate purpose or client_cert_chain_invalid_eku
    The client certificate does not have the required Extended Key Usage (EKU) attribute (specifically "Client Authentication") to be used for mTLS.

  • No client certificate presented or client_cert_not_provided
    The client did not send a certificate when the server requested one during the handshake.

  • client_cert_invalid_rsa_key_size or client_cert_unsupported_elliptic_curve_key
    The certificate uses an algorithm or key size that is not supported by the validating system.

  • hostname mismatch
    The hostname in the server's certificate does not match the domain name the client is trying to connect to.


Did this page help you?