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.
Defense in depth — each layer a request must pass before reaching the application
Separates public APIs (port 8080) from internal monitoring (port 9001). Your firewall controls which ports are reachable from the internet.
Encrypts all traffic with TLS 1.2/1.3. Supports server certificates, mutual TLS with client certs, and custom cipher suites.
Validates credentials on every request. Supports JWT bearer tokens, Resource Owner Password (ROPC), and LDAP bind.
Evaluates allow/deny rules against the authenticated identity. Deny-by-default when authentication is enabled.
Network isolation
Section titled “Network isolation”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.
TLS configuration
Section titled “TLS configuration”Run HTTPS in production. Never expose plaintext HTTP to untrusted networks.
Server certificates
Section titled “Server certificates”http.ssl { enabled = true cert = "/etc/scribe/tls/server.pem" key = "/etc/scribe/tls/server.key"}Or via environment variables:
SCRIBE_HTTP_SSL_ENABLED=trueSCRIBE_HTTP_SSL_CERT=/etc/scribe/tls/server.pemSCRIBE_HTTP_SSL_KEY=/etc/scribe/tls/server.keymTLS for API clients
Section titled “mTLS for API clients”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 oneREQUIRED— Reject connections without a valid client certificate
Protocol and cipher configuration
Section titled “Protocol and cipher configuration”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 ]}Authentication enforcement
Section titled “Authentication enforcement”By default, authentication is disabled. Enable it for protected deployments. The default access rules deny anonymous access and allow authenticated requests.
SCRIBE_AUTH_ENABLED=trueSCRIBE_AUTH_ISSUER=https://auth.example.com/realms/mycompanyThis configuration:
- Extracts and validates credentials from every request
- Returns 401 for requests without valid credentials
- Validates JWTs against your identity provider’s JWKS
Choosing an authentication method
Section titled “Choosing an authentication method”| Situation | Method | Why |
|---|---|---|
| Modern apps with OAuth/OIDC | bearer | Bearer tokens validated offline, no per-request IdP calls |
| Legacy apps that send username/password | ropc | Exchanges credentials for tokens at runtime |
| Internal tools with LDAP users | ldap | Direct 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"] }}Token validation
Section titled “Token validation”The defaults work for most setups. Tighten them if your security policy requires it.
Restrict signing algorithms
Section titled “Restrict signing algorithms”Only allow algorithms your IdP actually uses:
auth.jwt.allowed-algorithms = [RS256, ES256]Never include none in this list. It disables signature verification entirely.
Limit token lifetime
Section titled “Limit token lifetime”Reject tokens that claim to be valid for more than 8 hours:
auth.jwt.max-lifetime = 480The value is in minutes. Default is 1440 (24 hours).
Require expiration claims
Section titled “Require expiration claims”This is enabled by default. Keep it that way:
auth.jwt.require-expiration = trueTokens without exp claims never expire, which is a security risk.
Credential caching
Section titled “Credential caching”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 = 1mOr disable completely:
auth.ropc.cache.ttl = 0auth.ldap.cache.ttl = 0Disabling the cache means every request hits your IdP or LDAP server. Size your infrastructure accordingly.
LDAP connection security
Section titled “LDAP connection security”When using LDAP for sync or authentication, encrypt the connection.
Use LDAPS or StartTLS
Section titled “Use LDAPS or StartTLS”ldap { url = "ldaps://directory.example.com:636"}Or with StartTLS on the standard port:
ldap { url = "ldap://directory.example.com:389" start-tls = true}Certificate verification
Section titled “Certificate verification”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.
Filter locked accounts
Section titled “Filter locked accounts”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.
Database security
Section titled “Database security”Connection encryption
Section titled “Connection encryption”Enable SSL for PostgreSQL connections:
SCRIBE_DATABASE_SSL_ENABLED=trueOr in HOCON:
database.ssl.enabled = trueCredential management
Section titled “Credential management”Never commit database passwords to version control. Use environment variables:
SCRIBE_DATABASE_PASSWORD=your-passwordOr reference external secret stores in your deployment configuration (Kubernetes secrets, Vault, etc.).
Secrets management
Section titled “Secrets management”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}}Filesystem permissions
Section titled “Filesystem permissions”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 exposure
Section titled “API schema exposure”API schema endpoints reveal internal data structures. The default auto mode disables them in production while allowing access during development.
REST OpenAPI
Section titled “REST OpenAPI”channels.rest.openapi.enabled = falseOr via environment variable:
SCRIBE_REST_OPENAPI_ENABLED=falseAffected endpoints: /api.json, /api.yaml, /openapi.json, /openapi.yaml
GraphQL introspection
Section titled “GraphQL introspection”channels.graphql.introspection.enabled = falseOr via environment variable:
SCRIBE_GRAPHQL_INTROSPECTION_ENABLED=falseAffected endpoints: /graphql.json, /graphql.sdl, and introspection queries ({ __schema { ... } })
Interactive UIs
Section titled “Interactive UIs”Both Scalar (REST) and GraphiQL (GraphQL) UIs also default to auto:
channels.rest.ui.enabledchannels.graphql.ui.enabled
Go-live checklist
Section titled “Go-live checklist”Before deploying, verify each item:
Network
Section titled “Network”- Monitoring endpoints isolated from public network
- Firewall rules block direct database access
- TLS enabled on all public endpoints
Authentication
Section titled “Authentication”-
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
LDAP (if used)
Section titled “LDAP (if used)”- LDAPS or StartTLS enabled
- Server certificate verified
- Service account has minimal required permissions
- Filter excludes locked/disabled accounts
Secrets
Section titled “Secrets”- No secrets in version control
- Environment variables or secret manager for credentials
- Config files have restricted permissions
-
channels.rest.openapi.enabledisautoorfalse -
channels.rest.ui.enabledisautoorfalse -
channels.graphql.introspection.enabledisautoorfalse -
channels.graphql.ui.enabledisautoorfalse
Logging
Section titled “Logging”- Logs don’t contain sensitive data (passwords, tokens)
- Log files have appropriate retention and access controls
Related
Section titled “Related”- Authentication — Method configuration and access rules
- Networking — Socket model and TLS setup
- SSL configuration reference — All TLS options
- Auth configuration reference — All authentication options