Security
spark-connect-js handles TLS and bearer-token authentication through the connection string. Token-over-insecure is rejected unconditionally; anything beyond that (custom CAs, mTLS, custom verify callbacks) drops down to GrpcTransportOptions. The full URL parameter reference lives in Configuration.
Spark Connect 4.0’s gRPC server listens in plaintext. Production deployments terminate TLS at a reverse proxy in front of the port, and use_ssl=true on the connection string makes spark-connect-js do the TLS handshake against that proxy. Spark itself never sees the encrypted bytes.
connect("sc://spark.internal:443/;use_ssl=true");use_ssl=true swaps the underlying gRPC channel to grpc.credentials.createSsl(), which trusts whatever roots Node’s TLS layer trusts (the bundled Mozilla CA list plus anything in NODE_EXTRA_CA_CERTS). For a self-signed or private-CA cert, point NODE_EXTRA_CA_CERTS at the CA bundle before starting the process. For a custom ChannelCredentials (mTLS, custom verify callback), drop down to GrpcTransportOptions.channelCredentials; see the Node integration page.
The node-tls-behind-proxy example demonstrates the full deployment topology end to end with Caddy in front of apache/spark:4.0.0.
Bearer tokens
Section titled “Bearer tokens”connect("sc://spark.internal:443/;token=abc;use_ssl=true");The token is attached as authorization: Bearer <token> on every RPC via combineChannelCredentials(createSsl(), createFromMetadataGenerator(...)). The presence of token= implicitly enables TLS; an explicit use_ssl=false together with token= is rejected at parse time.
Token rotation
Section titled “Token rotation”Once a session is built, the bearer token is sealed into the channel and can’t be swapped in place. To rotate, build a new session with the new token, drain in-flight queries on the old session, then call stop() on it.
const stale = oldSession;const fresh = connect(`sc://spark.internal:443/;token=${newToken};use_ssl=true`);await drain(stale);await stale.stop();Custom metadata
Section titled “Custom metadata”Any unreserved ;key=value pair on the URL is attached to every RPC as gRPC metadata. Use it for tenant tags or proxy-auth headers your reverse proxy expects.
connect("sc://spark.internal:443/;use_ssl=true;tenant=acme;x-deploy=blue");Reserved keys are token, user_id, session_id, use_ssl, user_agent, and grpc_max_message_size.
What goes on the wire
Section titled “What goes on the wire”Each RPC carries the spark.connect.Plan (or analyze/config/interrupt request) in the body, plus metadata:
user-agent:<your prefix> spark-connect-js/<version> (node <version>; <platform>).authorization: Bearer <token>if a token is configured.client_observed_server_side_session_id: the most recentserverSideSessionIdthe server has emitted for this session, echoed back so the server can detect a stale-session mismatch. Cleared onReleaseSession.- Any unreserved connection-string params, as-is.
Residual gaps
Section titled “Residual gaps”| Feature | Status |
|---|---|
Mutual TLS via the public connect() URL | Not implemented. Achievable today through GrpcTransportOptions.channelCredentials directly. |
Request IDs / trace propagation (x-request-id, grpc-trace-bin) | Not implemented. Set them yourself via custom metadata params if a proxy needs them. |
| OAuth refresh-token flows | Not implemented. Wrap your token source in code that builds a new session when the bearer expires. |
Reporting a vulnerability
Section titled “Reporting a vulnerability”SECURITY.md has the disclosure policy. Don’t file security issues on the public tracker.