PCI Vault Logo
mTLS Authentication

This guide will help you authenticate with a third party that requires mutual TLS (mTLS) when you send them data using the Proxy API.

With mTLS, the third party doesn't just verify who you are with a client certificate, it also requires that certificate to be presented on every request. PCI Vault can generate the key pair and Certificate Signing Request (CSR) for you, import the certificate once it has been signed, and then use it automatically on your behalf whenever you make a proxy POST request.

Overview

Setting up and using mTLS with PCI Vault is a 4-step process.

  1. Generate a Certificate Signing Request (CSR).
  2. Send the CSR to the third party (or your own Certificate Authority) to be signed, and obtain the resulting certificate.
  3. Import the certificate data
  4. Reference the imported certificate when making proxy requests to the third party.
┌───────────┐             ┌─────────┐        ┌───────────┐
│Your Server│             │PCI Vault│        │Third Party│
└─────┬─────┘             └────┬────┘        └─────┬─────┘
      │1) Create CSR           │                   │      
      │───────────────────────>│                   │      
      │                        │                   │      
      │2) Send CSR             │                   │      
      │───────────────────────────────────────────>│      
      │                        │                   │      
      │3) Import Certificate   │                   │      
      │───────────────────────>│                   │      
      │                        │                   │      
      │4) Proxy Request        │                   │      
      │───────────────────────>│                   │      
      │                        │                   │      
      │                        │5) mTLS Request    │      
      │                        │──────────────────>│      
┌─────┴─────┐             ┌────┴────┐        ┌─────┴─────┐
│Your Server│             │PCI Vault│        │Third Party│
└───────────┘             └─────────┘        └───────────┘

Step 1: Create a Certificate Signing Request

Make a POST request to /proxy/csr with the domain attributes for the certificate you need.

For example, this Python code:

import requests
from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth('user', 'password')

url = "https://api.pcivault.io/v1/proxy/csr"
body = {
  "cn": "example.com",
  "o": "Some organisation",
  "ou": "IT Department",
  "l": "Houston",
  "st": "Texas",
  "c": "US"
}

res = requests.post(url, auth=auth, json=body)

# do something with the response
print(res)
print(res.text)

should return a JSON object like this:

{
  "id": "5aT9RDLTTUFam3cXRRs38i",
  "cn": "example.com",
  "o": "Some organisation",
  "ou": "IT Department",
  "l": "Houston",
  "st": "Texas",
  "c": "US",
  "data": "-----BEGIN CERTIFICATE REQUEST-----\nMIIEwjCCAqoCAQAwfTELMAk..."
}

PCI Vault generates a key pair behind the scenes and embeds the public key in the CSR. The private key never leaves PCI Vault and cannot be retrieved. Make a note of the id, you'll need it later to import the signed certificate.

You can list or fetch existing CSRs at any time using GET /proxy/csr, and remove one with DELETE /proxy/csr.


Note: Don't delete a CSR after generating a certificate from it. It holds the key pair needed to use that certificate for mTLS.


Step 2: Send the CSR to receive a signed certificate

Send the data field from Step 1 to the third party or Certificate Authority responsible for signing certificates. Exactly how you do this depends on the third party, they'll typically have their own onboarding process for accepting a CSR and issuing a certificate.

Step 3: Import the Signed Certificate

Once you receive the signed certificate back, import it using POST /proxy/cert. The body of the request is the raw PEM encoded certificate data, and the csr_id query parameter must reference the CSR id from Step 1.

For example:

import requests
from requests.auth import HTTPBasicAuth

auth = HTTPBasicAuth('user', 'password')

url = "https://api.pcivault.io/v1/proxy/cert"
csr_id = "5aT9RDLTTUFam3cXRRs38i"
pem_data = """-----BEGIN CERTIFICATE-----
MIIEwjCCAqoCAQAwfTELMAk...
-----END CERTIFICATE-----"""

res = requests.post(f'{url}?csr_id={csr_id}', auth=auth, data=pem_data)

# do something with the response
print(res)
print(res.text)

should return a JSON object like this:

{
  "id": "BYunQsKzpBqTmAwaNrBFjc",
  "csr_id": "5aT9RDLTTUFam3cXRRs38i",
  "data": "-----BEGIN CERTIFICATE-----\nMIIEwjCCAqoCAQAwfTELMAk...\n-----END CERTIFICATE-----",
  "expiry": "2025-09-06T14:20:42.312100551Z"
}

Make a note of the returned id, you'll use it as the client_cert_id when making proxy requests in Step 3.

You can list or fetch existing certificates at any time using GET /proxy/cert, and remove one with DELETE /proxy/cert.


Note: The CSR referenced by csr_id must not be deleted, as it holds the key pair needed to use the imported certificate.


Step 4: Use the Certificate to Make Proxy Requests

With the certificate imported, you can now use it on any POST request to /proxy/post by including its id as the client_cert_id field of the request object. PCI Vault will present the certificate as part of the mTLS handshake when it sends the request to the third party.

For example:

{
  "request": {
    "method": "POST",
    "url": "https://example-psp.com/process",
    "client_cert_id": "BYunQsKzpBqTmAwaNrBFjc",
    "headers": [
      {"Content-Type": "application/json"}
    ],
    "body": "{\"mustache_template\": \"{{number}}\"}"
  },
  "webhook": {
    "url": "https://reply-to.me",
    "secret": "rIx9tXqTH10_ShEThqQZ2yRI0e9_aPP9"
  }
}

Aside from client_cert_id, this works exactly the same as any other proxy POST request: PCI Vault will compile your mustache template with the data associated to the provided token, send the request to the third party (now authenticated with the client certificate), and return the response to you via webhook or synchronously.

If the certificate has expired, or its id no longer exists, the request to the third party will fail. Make sure to renew and re-import your certificate before it expires, using either the same CSR or creating a new one.