NIN Connect Docs
Platform (Self-Host)Security

Environment Variables

Startup validation, required variables, and secure configuration for NIN Connect.

Overview

NIN Connect validates all security-critical environment variables at startup using a Zod schema. If any required variable is missing or malformed, the application crashes immediately rather than running in a degraded or insecure state.

This eliminates an entire class of bugs where a missing encryption key or database URL silently causes failures at runtime.

Validation Schema

The validation lives in lib/env.ts and runs when the module is first imported:

import { z } from "zod";

const envSchema = z.object({
  DATABASE_URL: z.string().min(1),
  ENCRYPTION_KEY: z.string().length(64, "Must be 64-char hex (32 bytes)"),
  NEXT_PUBLIC_APP_URL: z.string().url(),
  FIREBASE_ADMIN_PROJECT_ID: z.string().min(1),
  FIREBASE_ADMIN_CLIENT_EMAIL: z.string().min(1),
  FIREBASE_ADMIN_PRIVATE_KEY: z.string().min(1),
});

export const env = envSchema.parse(process.env);

All server-side modules import from env instead of reading process.env directly. This ensures:

  • No undefined values slip through
  • ENCRYPTION_KEY is exactly 64 hex characters (32 bytes)
  • NEXT_PUBLIC_APP_URL is a valid URL
  • Firebase credentials are present before the Admin SDK initializes

No Fallback Keys

Previous versions used a fallback value for HMAC signing when ENCRYPTION_KEY was not set:

// BEFORE (insecure)
const secret = process.env.ENCRYPTION_KEY ?? "fallback-dev-key";

This meant the app could run with a publicly known signing key in production. The fallback has been removed. The sign() function now reads from the validated env.ENCRYPTION_KEY, which is guaranteed to exist and be the correct length.

Required Variables

VariablePurposeFormat
DATABASE_URLPostgreSQL connection stringpostgresql://...
ENCRYPTION_KEYAES-256-GCM encryption and HMAC signing64-char hex string
NEXT_PUBLIC_APP_URLBase URL for OAuth callbacks and connect pageshttps://your-domain.com
FIREBASE_ADMIN_PROJECT_IDFirebase Admin SDK projectString
FIREBASE_ADMIN_CLIENT_EMAILFirebase Admin SDK service accountEmail string
FIREBASE_ADMIN_PRIVATE_KEYFirebase Admin SDK private keyPEM string

Generating an Encryption Key

openssl rand -hex 32

Or using Node.js:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

.env.example

The repository includes a .env.example file with placeholder values for all required variables. Copy it and fill in real values:

cp .env.example .env.local

The .gitignore excludes all .env* files except .env.example, so real secrets are never committed.

On this page