Relationships
#1794 --ca-cert / SWAMP_CA_CERT are ignored when serve runs --auth-mode token — only DENO_CERT reaches the connection's TLS config (found validating #1748)
Opened by psftw · 8/23/2026· Shipped 8/24/2026
Description
When the target swamp serve runs --auth-mode token, the client's custom
trust anchor is never applied: --ca-cert <pem> and SWAMP_CA_CERT are both
ignored and the connection fails at the TLS handshake with
TLS certificate rejected: the server's certificate issuer is not trusted.
If using a self-signed certificate, pass it with --ca-cert /path/to/cert.pem
or set SWAMP_CA_CERT=/path/to/cert.pem— the advice the error gives is the thing that does not work. The identical
client command with the identical cert succeeds when the serve runs
--auth-mode none, so the anchor is plumbed on that path and lost on the
token path.
Deno's own DENO_CERT env var does reach the token path: with it set, the
handshake completes and the request proceeds to WebSocket auth (the server
logs WebSocket auth rejected … for a bogus token; a valid token round-trips
normally). That suggests the token-auth connection is made through the default
Deno fetch/WebSocket TLS stack rather than the client that receives the
--ca-cert TLS options.
This bites exactly where TLS is mandatory: serve refuses off-loopback binds
without TLS and without token/oauth auth, so a private direct listener (the
#1748 case — the ALPN fix itself works, thanks) can only be trusted via the
undocumented DENO_CERT workaround. A CA-signed leaf (proper CA:TRUE root,
leaf with IP SAN + serverAuth EKU, chain served) fails identically in token
mode, so it is not a self-signed-anchor quirk — the anchor simply is not
installed.
Steps to reproduce
The pair below differs only in the server's --auth-mode; loopback keeps
every other variable out.
swamp repo init repo --tool none
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
-days 2 -subj "/CN=localhost" \
-addext "subjectAltName=IP:127.0.0.1" \
-addext "basicConstraints=critical,CA:FALSE" \
-keyout t.key -out t.crt
# 1) auth-mode none — --ca-cert honored
swamp serve --repo-dir repo --host 127.0.0.1 --port 9443 \
--cert-file t.crt --key-file t.key &
swamp version --server wss://127.0.0.1:9443 --ca-cert t.crt
# -> succeeds
# 2) auth-mode token — same cert, same client command
kill %1
swamp serve --repo-dir repo --host 127.0.0.1 --port 9443 \
--cert-file t.crt --key-file t.key \
--auth-mode token --admins user:x &
swamp version --server wss://127.0.0.1:9443 --ca-cert t.crt
# -> TLS certificate rejected: the server's certificate issuer is not trusted
SWAMP_CA_CERT=$PWD/t.crt swamp version --server wss://127.0.0.1:9443
# -> same rejection
# 3) DENO_CERT reaches the token path
DENO_CERT=$PWD/t.crt swamp version --server wss://127.0.0.1:9443
# -> TLS completes; fails at auth as expected for a tokenless call:
# "Authentication failed — run: swamp auth server-login ..."Environment
- swamp 20260822.221619.0-sha.b65edcb8 (client and server the same build)
- Debian 13, linux amd64
- Also reproduced with an off-loopback bind (where token mode is mandatory) and with a CA-signed chain instead of a self-signed anchor
Shipped
Click a lifecycle step above to view its details.