Skip to main content
PensionsPortal.ie enforces a strict no-secrets-in-code policy. All sensitive values are managed through Vercel environment variables and are never committed to the repository.

Principles

  1. No hardcoded secrets — the codebase contains zero plaintext secrets, keys, or credentials
  2. .env.example for documentation only — placeholder values show the expected format; real values are never in .gitignore-excluded files committed to CI artefacts
  3. Principle of least privilege — each secret is used by exactly one component; no shared credentials
  4. Rotation without deployment — Vercel environment variables can be rotated without code changes (except AUTH_SECRET, which invalidates all sessions on rotation)

Required Environment Variables

VariableComponentNotes
DATABASE_URLDrizzle ORM / NeonPooled connection string. Rotated via Neon console.
DATABASE_URL_UNPOOLEDDrizzle migrations onlyDirect connection for drizzle-kit migrate. Not used at runtime.
AUTH_SECRETAuth.jsSigns JWTs. Rotation invalidates all active sessions. Generate: openssl rand -hex 32
AUTH_URLAuth.jsCanonical app URL for callback construction
PPS_ENCRYPTION_KEYMember PPS encryption64-character hex string (32 bytes / 256-bit AES key). Generate: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
ANTHROPIC_API_KEYAI featuresScoped to EU inference via ANTHROPIC_INFERENCE_GEO=EU
RESEND_API_KEYEmail (Resend)Used for password reset and notification emails
RAG_INGEST_SECRETRAG corpus ingestBearer token protecting POST /api/rag/ingest
SENTRY_AUTH_TOKENSentry source mapsUpload-only token for CI. Not present at runtime.

Vercel Environment Variable Management

Secrets are stored in Vercel project settings under Environment Variables. Vercel:
  • Encrypts secrets at rest
  • Injects them into the build and runtime environment
  • Does not expose them in build logs (values are masked)
  • Supports per-environment overrides (production / preview / development)
Preview deployments on Vercel inherit environment variables. Review access controls on preview deployments to ensure that preview environments do not expose production secrets to unauthorised parties.

PPS Encryption Key

The PPS_ENCRYPTION_KEY requires special handling:
  • Must be a 64-character hex string (32 bytes = 256-bit AES-256 key)
  • Generated once and stored only in Vercel environment variables
  • If lost, all stored PPS numbers become unrecoverable without the original key
  • Rotation requires re-encrypting all stored PPS numbers — a planned maintenance procedure, not a hotfix
# Generate a new PPS_ENCRYPTION_KEY
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

AUTH_SECRET Rotation

Rotating AUTH_SECRET:
  1. Generate a new secret: openssl rand -hex 32
  2. Update the Vercel environment variable
  3. Trigger a redeployment
  4. All existing user sessions are immediately invalidated — users must log in again
Plan rotation during low-traffic periods and communicate to users in advance.

What Must Never Appear in Code or Logs

  • Database connection strings (including usernames and passwords)
  • AUTH_SECRET value
  • PPS_ENCRYPTION_KEY value
  • ANTHROPIC_API_KEY
  • RESEND_API_KEY
  • Any bearer token or API key
The security test suite (src/tests/api/security.test.ts) verifies that connection strings and env var names are never exposed in API error responses.

Developer Workflow

Developers use a local .env.local file (gitignored) for development secrets. This file is never committed. The .env.example file in the repository contains safe placeholder values and serves as documentation.