Skip to content

feat(http-server): add TLS and mTLS termination#2808

Open
Ignacio-Vidal wants to merge 1 commit into
stoplightio:masterfrom
Ignacio-Vidal:feature/tls-mtls-termination
Open

feat(http-server): add TLS and mTLS termination#2808
Ignacio-Vidal wants to merge 1 commit into
stoplightio:masterfrom
Ignacio-Vidal:feature/tls-mtls-termination

Conversation

@Ignacio-Vidal

Copy link
Copy Markdown

Summary

Adds TLS termination (serve HTTPS) and mTLS termination (require/verify client certificates) to the Prism HTTP server, for both mock and proxy. It is fully opt-in: with no TLS flags, Prism serves plain HTTP exactly as before.

Lets Prism stand in for an API that is fronted by TLS/mTLS — e.g. mock or contract-test a service that requires HTTPS or client certs, without putting a real TLS gateway in front.

How it works

Prism's server framework (micri) only creates plain http servers, so the TLS path is built on Node's built-in modules instead:

  • TLS/mTLS uses https.createServer(tlsOptions, handler) (and http2.createSecureServer for --tls-http2).
  • Micri is still used for all request handling — the same router/handler runs requests via Micri's run() in the TLS path, so routing, CORS, and the mock/validate/proxy pipeline are unchanged.
  • Node's tls layer performs the handshake and client-certificate verification; Prism just passes the options through.
  • No changes to @stoplight/prism-core or @stoplight/prism-http — TLS is purely a server-transport concern.

Flags (available on both mock and proxy)

Flag Purpose
--tls-key <path> PEM private key. Enables HTTPS with --tls-cert.
--tls-cert <path> PEM server certificate (may include chain).
--tls-passphrase <str> Passphrase for an encrypted key.
--tls-ca <path> PEM CA bundle to verify client certs → enables mTLS.
--mtls Require + reject on failed client-cert verification (needs --tls-ca).
--tls-forward-client-cert Inject verified client identity as x-client-cert-subject / -san / -fingerprint / -verified request headers.
--tls-http2 Serve HTTP/2 over TLS, with HTTPS/1.1 fallback (ALPN).

The CLI reads the PEM files (clear errors on missing/unreadable files) and validates flag combinations (e.g. --mtls requires --tls-ca; TLS requires both key and cert). When TLS is active, the reported listen address switches to https://.

# TLS termination
prism mock api.oas.yaml --tls-key server.key --tls-cert server.crt

# mTLS termination + forward client identity
prism mock api.oas.yaml \
  --tls-key server.key --tls-cert server.crt \
  --tls-ca ca.crt --mtls --tls-forward-client-cert

Testing

  • Added unit tests (packages/http-server/src/__tests__/tls.spec.ts) using openssl-generated certs: TLS serves HTTPS (200); mTLS rejects a request with no client cert and accepts one with a valid client cert.
  • Manually validated end to end: HTTPS 200 + plain-HTTP-to-TLS-port rejected; mTLS reject/accept; x-client-cert-* headers injected; HTTP/2 (proto=2) with HTTPS/1.1 fallback.

Checklist

  • The basics
    • I tested these changes manually in my local or dev environment
  • Tests
    • Added or updated
  • Event Tracking
    • N/A
  • Error Reporting
    • N/A

Lets Prism serve HTTPS and optionally require/verify client certificates,
for both mock and proxy. Plain HTTP behaviour is unchanged when no TLS flags
are given.

- TLS termination: --tls-key / --tls-cert serve HTTPS via https.createServer,
  reusing Micri's router/handler (Micri's serve() is http-only). Reported
  address switches to https://. Supports --tls-passphrase for encrypted keys.
- mTLS termination: --tls-ca + --mtls request and verify the client cert at
  the handshake; unauthorized clients are rejected before reaching the handler.
- Client identity passthrough: --tls-forward-client-cert injects the verified
  client cert subject/SAN/SHA-256 fingerprint as x-client-cert-* request
  headers.
- HTTP/2: --tls-http2 serves over HTTP/2 with HTTPS/1.1 fallback (ALPN).
- Flags added to shared options (mock + proxy); CLI reads PEM files with clear
  errors and validates flag combinations.
- Unit tests for TLS and mTLS (accept/reject) using openssl-generated certs.
@Ignacio-Vidal Ignacio-Vidal requested a review from a team as a code owner June 14, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant