Skip to main content
Safe Online Exam reads all of its runtime settings from process environment variables. The application does not load .env files itself — Compose explicitly supplies an environment file, and local development uses .env.example as a reference only. This page documents every variable the application accepts, the validation rules applied in hardened runtimes, and the deployment-template guidance that prevents misconfiguration.
Do not combine deployment templates blindly. Variables such as APP_IMAGE, PROJECT_ID, and PUBLIC_HOST are consumed by deployment scripts and Compose itself — they are not application runtime settings. Start from the single template that matches your topology: .env.example for a source checkout, .env.compose.example or .env.compose.secrets.example for Compose, or deploy/cloudrun.env.example for Cloud Run.

Profiles and Validation

The application resolves its runtime profile from the first non-empty value among APP_ENV, NODE_ENV, and the compatibility alias SPRING_PROFILES_ACTIVE.
Hardened validation is always active in production (APP_ENV=prod) and on any Cloud Run service regardless of profile — including an isolated APP_ENV=dev service. When hardened validation is active, the application performs strict checks on every database, Canvas, LTI, OAuth, secret, URL, and certificate value and terminates at startup before listening if any value is missing or unsafe. There is no partial startup.
The parser retains a small number of historical aliases — including APP_BASE_URL, CANVAS_BASE_URL, DEPLOYMENT_ID, and the DEV_*/PROD_* credential names — for maintained deployments. New installations should use only the canonical names documented here. In a hardened runtime, any supplied APP_BASE_URL or BASE_URL must exactly match TOOL_URL.

Critical Application Variables

string
required
Public HTTPS origin of this Safe Online Exam deployment. Must be an HTTPS origin with no path, query string, credentials, or fragment. This value is used in LTI launch verification, Canvas OAuth redirect validation, and SEB configuration generation.Example: https://seb-tool.example.edu
string
required
The HTTPS origin of the connected Canvas LMS installation. Must be an HTTPS origin only. Do not include a trailing slash or path segment. The application derives CANVAS_API_BASE_URL from this value when that variable is not explicitly set.Example: https://school.instructure.com
string
required
The client ID from the Canvas LTI 1.3 Developer Key created for this tool. This value must match the aud claim in LTI launch tokens issued by Canvas.Example: 170000000000042
string
required
Hostname, IP address, or Unix socket directory for the PostgreSQL server. Required in hardened runtimes. For Cloud SQL on Cloud Run, use the socket path format: /cloudsql/PROJECT:REGION:INSTANCE.Default: 127.0.0.1
string
required
Signing secret for Express session cookies. Must be at least 32 characters and must differ from STATE_ENCRYPTION_KEY. Rotating this value invalidates all active user sessions. Prefer the SESSION_SECRET_FILE alternative in production.

PostgreSQL Variables

PostgreSQL 17 or newer is the supported durable store. The application uses standard PostgreSQL protocol settings and is not tied to any managed provider. A VM or external managed PostgreSQL connection should normally use verify-full with a trusted certificate chain. If the provider uses a private certificate authority, mount the CA file and set NODE_EXTRA_CA_CERTS to that path before process startup. Cloud Run uses an authenticated Unix socket that is local to the Cloud Run sandbox, so DATABASE_SSL_MODE=disable is correct in that topology.

Required Application Values

These variables are validated in every hardened runtime. Startup fails before the server begins listening if any required value is absent or fails its format check.

Optional and Diagnostic Variables


File-Based Secrets

The following sensitive values each accept a mutually exclusive _FILE alternative that instructs the application to read the secret from a file path rather than a direct environment variable. Files are read once during configuration startup. The application rejects any configuration where both the direct variable and its _FILE alternative are set simultaneously. Unreadable paths are reported without echoing any secret contents. Required-value validation rejects a missing or empty file result just as it would a missing direct variable. Docker and Kubernetes secret mounts work without any provider-specific SDK. For detailed guidance on secret file format, keyring structure, the Docker Compose secrets profile, and rotation procedures, see Managing Secrets and File-Based Configuration.