Mutual TLS for API Keys
Mutual TLS (mTLS) adds a second factor to API key authentication. With mTLS enforced on a key, a request to the Ingest API must present a client certificate issued by the certificate authority (CA) registered for your workspace. A leaked API key alone is no longer enough to call the API.
You register one CA per workspace and environment. mTLS is then switched on per API key. Keys without mTLS keep working exactly as before.
1. How it works
- You operate a CA that issues client certificates for your integration.
- You register that CA certificate once in Settings → Developer → Mutual TLS. spektr adds it to the truststore of the environment's mTLS hostname.
- You create an API key with Require mTLS client certificate switched on, or switch it on for an existing key.
- Your integration calls the mTLS hostname with a client certificate issued by your CA and the API key.
- spektr verifies the certificate chain at the edge, then checks that the certificate's issuer is your registered CA. Either check failing rejects the request.
Once mTLS is enforced on a key, it can only be used through the mTLS hostname with a certificate from your CA. The same key sent to the regular hostname, or with a certificate from another CA, is rejected with 401 Unauthorized.
2. Hostnames
Every environment has an mTLS variant of the Ingest API hostname. It serves the same API and paths; only the transport requirements differ.
| Environment | Standard hostname | mTLS hostname |
|---|---|---|
| Live | ingest.spektr.com | mtls-ingest.spektr.com |
| Sandbox | sandbox-ingest.spektr.com | sandbox-mtls-ingest.spektr.com |
| Test | test-ingest.spektr.com | test-mtls-ingest.spektr.com |
The mTLS hostname refuses the TLS handshake if no client certificate is presented or if the certificate does not chain to a CA in the truststore. Requests that fail here never reach spektr's application layer, so you will see a TLS error from your HTTP client rather than an HTTP status code.
Truststores and API keys are per environment, as described in Environments. Register your CA and switch on mTLS separately in each environment you use. You may use the same CA in all of them.
3. Prerequisites
Your certificate authority
- Use a dedicated CA (or intermediate) for your spektr integration. Do not register a public CA: anyone with a certificate from that CA could reach your mTLS hostname.
- The registered certificate must be the direct issuer of your client certificates. If you use an intermediate CA, register the intermediate.
- The certificate must be marked as a CA (
basicConstraints: CA:TRUE). Leaf certificates are refused. - Give the CA a distinctive subject, for example
CN=Acme spektr Integration CA,O=Acme Corp,C=US. Two workspaces cannot register CAs with the same subject. - Use RSA 2048-bit or larger, or ECDSA P-256 / P-384. The CA must not be expired.
- Paste the CA certificate on its own: exactly one PEM block. Bundles and chains are rejected.
Example with OpenSSL:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-keyout integration-ca.key -out integration-ca.crt -days 3650 \
-subj "/CN=Acme spektr Integration CA/O=Acme Corp/C=US" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign"Your client certificates
Issue as many client certificates from the registered CA as you need. The subject is free; spektr only checks the issuer.
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-keyout spektr-client.key -out spektr-client.csr \
-subj "/CN=spektr-integration/O=Acme Corp/C=US"
openssl x509 -req -in spektr-client.csr \
-CA integration-ca.crt -CAkey integration-ca.key -CAcreateserial \
-out spektr-client.crt -days 365 -sha2564. Register your CA
In Settings → Developer → Mutual TLS, paste the PEM encoded CA certificate and click Register CA. The page then shows the registered CA's subject, serial number, SHA-256 fingerprint and validity. Only the public certificate is read and stored; never paste a private key.
The truststore update can take a few minutes to reach the mTLS hostname. Use /v1/mtls-check (section 6) to confirm.
5. Switch mTLS on for an API key
API keys are managed in Settings → Developer → API keys. When generating a key, turn on Require mTLS client certificate. The switch is disabled until a CA is registered. The keys table shows Enforced for every key that requires mTLS, and the pencil icon on a row toggles it for an existing key.
6. Call the API
Send every request for an enforced key to the mTLS hostname with a client certificate from your CA. The API key header is unchanged.
curl https://mtls-ingest.spektr.com/v1/fields \
--cert spektr-client.crt --key spektr-client.key \
-H "x-api-key: <your api key>"Any HTTP client works the same way. Configure it with three things:
| Setting | Value |
|---|---|
| Client certificate | spektr-client.crt (PEM), issued by your registered CA |
| Client private key | spektr-client.key (PEM) |
| Request header | x-api-key: <your api key> |
Send the request to the mTLS hostname for your environment (section 2). No other headers, paths or payloads change.
Some clients, keystores and tools expect the certificate and key as a single PKCS#12 file (.p12 / .pfx) instead of two PEM files. Create one with:
openssl pkcs12 -export -inkey spektr-client.key -in spektr-client.crt \
-out spektr-client.p12OpenSSL prompts for an export password, which the client then needs to open the file.
To see which certificate identity spektr observed, call the check endpoint over the mTLS hostname with any key of the workspace:
curl https://mtls-ingest.spektr.com/v1/mtls-check \
--cert spektr-client.crt --key spektr-client.key \
-H "x-api-key: <your api key>"{
"clientCertificatePresented": true,
"issuerDN": "CN=Acme spektr Integration CA,O=Acme Corp,C=US",
"subjectDN": "CN=spektr-integration,O=Acme Corp,C=US",
"serialNumber": "4f2c1a9b3d7e5081"
}Expected outcomes:
| Request | Result |
|---|---|
| mTLS hostname, certificate from your CA, enforced key | Normal response |
| mTLS hostname, certificate from an unregistered CA | TLS handshake failure |
| mTLS hostname, certificate from another workspace's CA | 401 Unauthorized |
| Standard hostname, enforced key | 401 Unauthorized |
| mTLS hostname, certificate from your CA, key without mTLS | Normal response |
A 401 for an enforced key carries no detail in the body. Use /v1/mtls-check to see what identity spektr received.
7. Rotate or remove the CA
Client certificate renewals need no change in spektr as long as they are issued by the registered CA.
To rotate the CA itself, register the new CA certificate the same way as the first one. Registering replaces the previous CA: every key that enforces mTLS switches to the new CA at once, and the old CA is removed from the truststore. Plan the switch so your integration presents certificates from the new CA when you register it.
To stop using mTLS in an environment, switch it off on every key first, then click Remove CA or call DELETE /user/v1/api-keys/client-ca. Removal is refused with 400 while any key still requires mTLS.
CA expiry
spektr records the CA's validity period and shows it in Settings → Developer → Mutual TLS (validTo in the API response), but it does not yet alert you before the CA expires. Once the CA is past validTo, the mTLS hostname refuses the handshake for every certificate it issued and all enforced keys stop working. Track the expiry date on your side and rotate the CA ahead of it, following the steps above. Expiry notifications from spektr are planned.
8. Troubleshooting
| Symptom | Likely cause |
|---|---|
| TLS handshake error, no HTTP response | No client certificate sent, its CA is not registered in this environment, or the truststore has not refreshed yet. |
401 on the mTLS hostname with an enforced key | The certificate was not issued by the registered CA. Compare issuerDN from /v1/mtls-check with the CA subject shown in settings. |
401 on the standard hostname | The key requires mTLS. Use the mTLS hostname. |
403 Forbidden before any TLS or application error | Missing or invalid x-api-key header. |
| Works in Test but not Live | CA registration and API keys are per environment. |
400 when switching mTLS on | No CA registered in this environment. See section 4. |
409 when registering the CA | The CA subject is already taken by another workspace. Re-issue the CA with a distinctive name. |
Updated about 20 hours ago