Environment Variables (Configuration)
Shyntr follows the 12-Factor App methodology. All configurations are managed via environment variables. This document describes all available variables, their default values, and their purposes.
Environment variables take precedence over any config files. In containerized deployments, always use environment variables for configuration.
Core Server Settings
| Variable | Default | Description |
|---|---|---|
PORT | 7496 | Port for the Public API (SAML/OIDC endpoints) |
ADMIN_PORT | 7497 | Port for the Admin API (Dashboard and Auth Portal communication) |
ISSUER_URL | http://localhost:7496 | Base URL of the Identity Hub. Used in iss claims and SAML metadata |
LOG_LEVEL | info | Logging verbosity: debug, info, warn, error, fatal |
GO_ENV | development | Set to production for JSON logging and optimized behavior |
GIN_MODE | debug | Set to release in production to disable debug output |
PORT=7496
ADMIN_PORT=7497
ISSUER_URL=https://auth.yourcompany.com
LOG_LEVEL=info
GO_ENV=production
GIN_MODE=release
The ISSUER_URL must match exactly what clients expect in the iss claim of tokens. Changing this after deployment will invalidate all existing tokens.
Database Configuration
| Variable | Default | Description |
|---|---|---|
DSN | postgres://shyntr:secretpassword@localhost:5432/shyntr?sslmode=disable | PostgreSQL connection string |
DATABASE_URL | (alias for DSN) | Alternative variable name (Heroku compatible) |
DB_MAX_IDLE_CONNS | 10 | Maximum idle connections in the pool |
DB_MAX_OPEN_CONNS | 100 | Maximum open connections to the database |
DSN=postgres://shyntr:${DB_PASSWORD}@db.internal:5432/shyntr?sslmode=require
DB_MAX_IDLE_CONNS=25
DB_MAX_OPEN_CONNS=100
Connection String Format
postgres://[user]:[password]@[host]:[port]/[database]?[parameters]
Common parameters:
sslmode=disable- No SSL (development only)sslmode=require- Require SSLsslmode=verify-full- Require SSL with certificate verificationconnect_timeout=10- Connection timeout in seconds
Cryptography & Security
| Variable | Default | Description |
|---|---|---|
APP_SECRET | 12345678901234567890123456789012 | 32-byte string for AES-256-GCM encryption |
APP_PRIVATE_KEY_BASE64 | (empty) | Base64-encoded RSA private key (PKCS#1 or PKCS#8) |
COOKIE_SECURE | false | Set true in production (requires HTTPS) |
SKIP_TLS_VERIFY | false | Skip TLS verification on outbound requests |
APP_SECRET must be:
- Exactly 32 bytes (characters)
- Cryptographically random
- Never committed to version control
- Rotated carefully (existing encrypted data becomes unreadable)
Generate a secure secret:
openssl rand -hex 16
# or
head -c 32 /dev/urandom | base64 | head -c 32
RSA Key Configuration
If APP_PRIVATE_KEY_BASE64 is empty, Shyntr auto-generates an RSA key pair and stores it encrypted in the database. To use your own key:
# Generate 2048-bit RSA key
openssl genrsa -out private.pem 2048
# Base64 encode for environment variable
cat private.pem | base64 -w 0
APP_PRIVATE_KEY_BASE64="LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ..."
Never set SKIP_TLS_VERIFY=true in production. This disables certificate validation for outbound HTTPS requests (OIDC Discovery, etc.), exposing you to man-in-the-middle attacks.
Headless UI Routing (Auth Portal)
These URLs configure where Shyntr redirects users for authentication UI:
| Variable | Default | Description |
|---|---|---|
EXTERNAL_LOGIN_URL | http://localhost:3000/login | Login page URL |
EXTERNAL_CONSENT_URL | http://localhost:3000/consent | Consent page URL |
EXTERNAL_LOGIN_URL=https://auth-portal.yourcompany.com/login
EXTERNAL_CONSENT_URL=https://auth-portal.yourcompany.com/consent
Shyntr appends challenge parameters to these URLs:
https://auth-portal.yourcompany.com/login?login_challenge=abc123...
https://auth-portal.yourcompany.com/consent?consent_challenge=xyz789...
Token Lifespans
| Variable | Default | Description |
|---|---|---|
ACCESS_TOKEN_LIFESPAN | 1h | Default access token lifetime |
ID_TOKEN_LIFESPAN | 1h | Default ID token lifetime |
REFRESH_TOKEN_LIFESPAN | 720h (30 days) | Default refresh token lifetime |
Format: Duration string with unit suffix:
15m= 15 minutes1h= 1 hour24h= 24 hours720h= 30 days
ACCESS_TOKEN_LIFESPAN=15m
ID_TOKEN_LIFESPAN=15m
REFRESH_TOKEN_LIFESPAN=24h
Token lifespans can be overridden per-client through the Admin API or CLI. The environment variables set global defaults.
Cross-Origin Resource Sharing (CORS)
| Variable | Default | Description |
|---|---|---|
CORS_ALLOWED_ORIGINS | http://localhost:3000,http://localhost:3274 | Origins for Public API |
ADMIN_CORS_ALLOWED_ORIGINS | http://localhost:3000,http://localhost:3274,http://localhost:7497 | Origins for Admin API |
CORS_ALLOWED_ORIGINS=https://app.yourcompany.com,https://mobile.yourcompany.com
ADMIN_CORS_ALLOWED_ORIGINS=https://auth-portal.yourcompany.com
- Never use
*(wildcard) in production - Only list origins that actually need access
- The Admin API should typically only allow your Auth Portal origin
Multi-Tenancy
| Variable | Default | Description |
|---|---|---|
DEFAULT_TENANT_ID | default | ID of the root tenant created on first migration |
DEFAULT_TENANT_ID=primary
Complete Production Example
# Core Server
PORT=7496
ADMIN_PORT=7497
ISSUER_URL=https://auth.yourcompany.com
LOG_LEVEL=info
GO_ENV=production
GIN_MODE=release
# Database
DSN=postgres://shyntr:${DB_PASSWORD}@db.internal:5432/shyntr?sslmode=verify-full
DB_MAX_IDLE_CONNS=25
DB_MAX_OPEN_CONNS=100
# Security (use secret management in practice)
APP_SECRET=${APP_SECRET}
APP_PRIVATE_KEY_BASE64=${RSA_PRIVATE_KEY}
COOKIE_SECURE=true
SKIP_TLS_VERIFY=false
# Auth Portal
EXTERNAL_LOGIN_URL=https://auth-portal.yourcompany.com/login
EXTERNAL_CONSENT_URL=https://auth-portal.yourcompany.com/consent
# Token Lifespans
ACCESS_TOKEN_LIFESPAN=1h
ID_TOKEN_LIFESPAN=1h
REFRESH_TOKEN_LIFESPAN=168h
# CORS
CORS_ALLOWED_ORIGINS=https://app.yourcompany.com
ADMIN_CORS_ALLOWED_ORIGINS=https://auth-portal.yourcompany.com
# Multi-Tenancy
DEFAULT_TENANT_ID=default
Environment Variable Validation
Shyntr validates critical variables on startup:
| Validation | Behavior |
|---|---|
APP_SECRET length ≠ 32 | Fatal error, won't start |
DSN invalid format | Fatal error, won't start |
ISSUER_URL invalid URL | Warning, may cause issues |
| Missing required variables | Uses defaults with warning |
Docker Secrets Integration
For Docker Swarm or Kubernetes, use file-based secrets:
services:
shyntr:
environment:
- APP_SECRET_FILE=/run/secrets/app_secret
- DSN_FILE=/run/secrets/database_url
secrets:
- app_secret
- database_url
secrets:
app_secret:
external: true
database_url:
external: true
Shyntr automatically reads *_FILE variants and loads the file contents as the variable value.
Next Steps
- Set up Docker Compose deployment
- Explore the CLI Reference for management
- Implement Headless Login & Consent