> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pensionsportal.ie/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets Management

> How PensionsPortal.ie manages API keys, database credentials, and encryption keys — with no hardcoded secrets.

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

| Variable                | Component               | Notes                                                                                                                                      |
| ----------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `DATABASE_URL`          | Drizzle ORM / Neon      | Pooled connection string. Rotated via Neon console.                                                                                        |
| `DATABASE_URL_UNPOOLED` | Drizzle migrations only | Direct connection for `drizzle-kit migrate`. Not used at runtime.                                                                          |
| `AUTH_SECRET`           | Auth.js                 | Signs JWTs. Rotation invalidates all active sessions. Generate: `openssl rand -hex 32`                                                     |
| `AUTH_URL`              | Auth.js                 | Canonical app URL for callback construction                                                                                                |
| `PPS_ENCRYPTION_KEY`    | Member PPS encryption   | 64-character hex string (32 bytes / 256-bit AES key). Generate: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` |
| `ANTHROPIC_API_KEY`     | AI features             | Scoped to EU inference via `ANTHROPIC_INFERENCE_GEO=EU`                                                                                    |
| `RESEND_API_KEY`        | Email (Resend)          | Used for password reset and notification emails                                                                                            |
| `RAG_INGEST_SECRET`     | RAG corpus ingest       | Bearer token protecting `POST /api/rag/ingest`                                                                                             |
| `SENTRY_AUTH_TOKEN`     | Sentry source maps      | Upload-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)

<Warning>
  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.
</Warning>

## 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

```bash theme={null}
# 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.
