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.
Setting up and using mTLS with PCI Vault is a 4-step process.
┌───────────┐ ┌─────────┐ ┌───────────┐
│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│
└───────────┘ └─────────┘ └───────────┘
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.
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.
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.
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.