Auth & Security

By default CntrlNode starts with no authentication — any client can read and write state. For production deployments, enable API key authentication.

Enable auth

Set these environment variables before starting the server:

CNTRLNODE_AUTH_ENABLED=true
CNTRLNODE_API_KEYS=key-abc123,key-def456

Or in config.yaml:

auth:
  enabled: true
  apiKeys:
    - key-abc123
    - key-def456

The /health endpoint is always public and never requires authentication.

Using API keys

Pass the key as a Bearer token in the Authorization header:

curl http://localhost:7474/v1/state/wf-1/status \
  -H "Authorization: Bearer key-abc123"

In the TypeScript SDK:

const client = new CntrlNodeClient({
  baseUrl: 'http://localhost:7474',
  apiKey: 'key-abc123',
})

In the Python SDK:

client = CntrlNodeClient(
    base_url="http://localhost:7474",
    api_key="key-abc123",
)

Generating keys

Use any cryptographically random string. A good approach:

# macOS / Linux
openssl rand -hex 32
# → e3b0c44298fc1c149afb...

# Or with Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Minimum recommended length: 32 bytes (64 hex characters).

Security model

  • Keys are compared using constant-time comparison (crypto/subtle.ConstantTimeCompare) to prevent timing attacks.
  • Keys are stored as plaintext in the config/env — protect your config files and environment accordingly.
  • There is no per-key ACL — all valid keys have full access. Role-based access control is planned for a future release.

TLS / HTTPS

CntrlNode does not terminate TLS itself. For production, put it behind a reverse proxy:

nginx

server {
    listen 443 ssl;
    server_name cntrlnode.mycompany.com;

    ssl_certificate /etc/ssl/certs/mycompany.crt;
    ssl_certificate_key /etc/ssl/private/mycompany.key;

    location / {
        proxy_pass http://127.0.0.1:7474;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Caddy (automatic HTTPS)

cntrlnode.mycompany.com {
    reverse_proxy localhost:7474
}

Docker Compose example (prod)

services:
  cntrlnode:
    image: ghcr.io/meetpatell07/cntrlnode:latest
    environment:
      CNTRLNODE_AUTH_ENABLED: "true"
      CNTRLNODE_API_KEYS: "${CNTRLNODE_API_KEYS}"
      CNTRLNODE_STORAGE: postgres
      CNTRLNODE_DB_URL: "${DATABASE_URL}"
    ports:
      - "7474:7474"

  caddy:
    image: caddy:2
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
    ports:
      - "443:443"
    depends_on:
      - cntrlnode

Recommendations

EnvironmentAuthTLS
Local devDisabledNot needed
StagingEnabled, single keyRecommended
ProductionEnabled, per-service keysRequired