Skip to content

Production Checklist

IdentityScribe ships with safe defaults for development — open ports, no TLS, no authentication. Walk through each section below and change what applies to your deployment.

Security layers

Defense in depth — each layer a request must pass before reaching the application

Network Isolation Active by default

Separates public APIs (port 8080) from internal monitoring (port 9001). Your firewall controls which ports are reachable from the internet.

Connection refused
TLS OFF by default

Encrypts all traffic with TLS 1.2/1.3. Supports server certificates, mutual TLS with client certs, and custom cipher suites.

TLS handshake failure
Authentication OFF by default

Validates credentials on every request. Supports JWT bearer tokens, Resource Owner Password (ROPC), and LDAP bind.

401 Unauthorized
Access Rules ON when auth enabled

Evaluates allow/deny rules against the authenticated identity. Deny-by-default when authentication is enabled.

403 Forbidden

Separate internal endpoints from public APIs. Monitoring and health endpoints should not be accessible from the internet.

http {
port = 8080
host = "0.0.0.0"
sockets.internal {
port = 9001
host = "127.0.0.1"
}
}
monitoring.socket = "internal"

With this setup:

  • REST, GraphQL, and MCP channels listen on port 8080 (all interfaces)
  • Prometheus metrics, health probes, and observability endpoints only respond on localhost:9001

Your firewall should block external access to port 9001.

Run HTTPS in production. Never expose plaintext HTTP to untrusted networks.

http.ssl {
enabled = true
cert = "/etc/scribe/tls/server.pem"
key = "/etc/scribe/tls/server.key"
}

Or via environment variables:

Terminal window
SCRIBE_HTTP_SSL_ENABLED=true
SCRIBE_HTTP_SSL_CERT=/etc/scribe/tls/server.pem
SCRIBE_HTTP_SSL_KEY=/etc/scribe/tls/server.key

Require client certificates when you control all API consumers. mTLS (mutual TLS) adds an extra layer of security:

http.ssl {
enabled = true
cert = "/etc/scribe/tls/server.pem"
key = "/etc/scribe/tls/server.key"
ca = "/etc/scribe/tls/client-ca.pem"
client-auth = "REQUIRED"
}

The client-auth options:

  • NONE — No client certificate required (default)
  • OPTIONAL — Request certificate but allow connections without one
  • REQUIRED — Reject connections without a valid client certificate

IdentityScribe defaults to TLS 1.2 and 1.3 with cipher suites from SSL Labs recommendations. These defaults follow current best practices. Only override if you have specific compliance requirements.

ssl {
protocols = [TLSv1.3, TLSv1.2]
cipher-suites = [
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
]
}

By default, authentication is disabled. Enable it for protected deployments. The default access rules deny anonymous access and allow authenticated requests.

Terminal window
SCRIBE_AUTH_ENABLED=true
SCRIBE_AUTH_ISSUER=https://auth.example.com/realms/mycompany

This configuration:

  • Extracts and validates credentials from every request
  • Returns 401 for requests without valid credentials
  • Validates JWTs against your identity provider’s JWKS
SituationMethodWhy
Modern apps with OAuth/OIDCbearerBearer tokens validated offline, no per-request IdP calls
Legacy apps that send username/passwordropcExchanges credentials for tokens at runtime
Internal tools with LDAP usersldapDirect LDAP bind, no IdP needed

Most deployments should use bearer. Add ropc or ldap only when you have clients that can’t obtain tokens themselves.

auth {
enabled = true
methods = [bearer]
providers.default {
issuer = "https://auth.example.com/realms/mycompany"
audiences = ["scribe"]
}
}

The defaults work for most setups. Tighten them if your security policy requires it.

Only allow algorithms your IdP actually uses:

auth.jwt.allowed-algorithms = [RS256, ES256]

Never include none in this list. It disables signature verification entirely.

Reject tokens that claim to be valid for more than 8 hours:

auth.jwt.max-lifetime = 480

The value is in minutes. Default is 1440 (24 hours).

This is enabled by default. Keep it that way:

auth.jwt.require-expiration = true

Tokens without exp claims never expire, which is a security risk.

ROPC and LDAP cache successful authentications. This speeds up repeated requests but delays password changes and account lockouts.

Caching means:

  • Password changes take effect after cache TTL expires
  • Revoked or locked accounts remain valid until cache expires
  • Reduced load on your IdP or LDAP server

For tighter security, reduce cache TTL:

auth.cache.ttl = 1m

Or disable completely:

auth.ropc.cache.ttl = 0
auth.ldap.cache.ttl = 0

Disabling the cache means every request hits your IdP or LDAP server. Size your infrastructure accordingly.

When using LDAP for sync or authentication, encrypt the connection.

ldap {
url = "ldaps://directory.example.com:636"
}

Or with StartTLS on the standard port:

ldap {
url = "ldap://directory.example.com:389"
start-tls = true
}

By default, IdentityScribe verifies the LDAP server’s certificate against the system trust store. For private CAs:

ldap.ssl {
ca = "/etc/scribe/tls/ldap-ca.pem"
}

Never set insecure = true in production. It disables certificate verification.

Prevent locked or disabled accounts from authenticating:

auth.ldap {
filter = "(!(accountLocked=TRUE))"
}

For Active Directory:

auth.ldap {
filter = "(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
}

This filter excludes accounts with the “disabled” flag set.

Enable SSL for PostgreSQL connections:

Terminal window
SCRIBE_DATABASE_SSL_ENABLED=true

Or in HOCON:

database.ssl.enabled = true

Never commit database passwords to version control. Use environment variables:

Terminal window
SCRIBE_DATABASE_PASSWORD=your-password

Or reference external secret stores in your deployment configuration (Kubernetes secrets, Vault, etc.).

Don’t put passwords or API keys in config files that get committed to git. Use environment variables or a secrets manager instead.

IdentityScribe supports ${?ENV_VAR} substitution in HOCON configs:

auth.providers.default {
client-secret = ${SCRIBE_AUTH_CLIENT_SECRET}
}

If you use config files with secrets:

  • Set file permissions to 600 (owner read/write only)
  • Run IdentityScribe as a dedicated service account
  • Mount config files as read-only in containers

API schema endpoints reveal internal data structures. The default auto mode disables them in production while allowing access during development.

channels.rest.openapi.enabled = false

Or via environment variable:

Terminal window
SCRIBE_REST_OPENAPI_ENABLED=false

Affected endpoints: /api.json, /api.yaml, /openapi.json, /openapi.yaml

channels.graphql.introspection.enabled = false

Or via environment variable:

Terminal window
SCRIBE_GRAPHQL_INTROSPECTION_ENABLED=false

Affected endpoints: /graphql.json, /graphql.sdl, and introspection queries ({ __schema { ... } })

Both Scalar (REST) and GraphiQL (GraphQL) UIs also default to auto:

  • channels.rest.ui.enabled
  • channels.graphql.ui.enabled

Before deploying, verify each item:

  • Monitoring endpoints isolated from public network
  • Firewall rules block direct database access
  • TLS enabled on all public endpoints
  • auth.enabled = true
  • Access rules configured (deny-by-default is automatic)
  • Provider issuer URL points to your IdP
  • Audiences configured to match your tokens
  • Valid certificates installed
  • Certificate expiration monitored
  • Private keys protected with appropriate filesystem permissions
  • LDAPS or StartTLS enabled
  • Server certificate verified
  • Service account has minimal required permissions
  • Filter excludes locked/disabled accounts
  • No secrets in version control
  • Environment variables or secret manager for credentials
  • Config files have restricted permissions
  • channels.rest.openapi.enabled is auto or false
  • channels.rest.ui.enabled is auto or false
  • channels.graphql.introspection.enabled is auto or false
  • channels.graphql.ui.enabled is auto or false
  • Logs don’t contain sensitive data (passwords, tokens)
  • Log files have appropriate retention and access controls