Credential Vault
Encrypted storage for third-party service credentials, and the grants that control who can read them.
Credential Vault
Third-party logins that do not belong in environment variables — a carrier portal, a
supplier account, a bank login — are stored encrypted in the database and read
through /admin/credentials.
Storage
ServiceCredential holds one credential:
| Field | Purpose |
|---|---|
serviceName, label | What this is |
username | Optional |
encValue, encIv, encTag | The secret, AES-256-GCM |
url, notes | Where to use it, and anything else |
createdById, updatedById | Who touched it |
passwordChangedAt | Last rotation |
Encryption is lib/crypto.ts: AES-256-GCM with a 128-bit IV and a 128-bit auth tag,
keyed by MASTER_KEY (ENCRYPTION_KEY is used for the same machinery
elsewhere). Both must be valid hex of the right length — crypto.ts validates
before decrypting rather than surfacing a raw cipher error.
Lose MASTER_KEY and every stored credential is unrecoverable. It is not derivable
from anything else. Keep it in Vercel environment variables and in whatever the team
uses for break-glass secrets — never in the repository.
The same encryption path secures QuickBooks OAuth tokens, social platform tokens, and admin-entered API credentials.
Who can read what
Two gates must both pass:
CredentialAccessGrant— a row keyed by email, with per-action flagscanView,canAdd,canEdit,canDelete,canUpload, and arevokedAtthat turns the grant off without deleting the audit trail.- The RBAC permission system — the
CREDENTIALSpermission category.
checkCredentialAccess(email, role) in lib/credentials.ts evaluates both and
returns 'read', 'write', or null. The designated super-admin account bypasses
the grant table, matching the admin page's own bypass.
Grant access with:
npm run credentials:grant-access --workspace @jose-madrid/storefrontIf the credential_access_grants table is missing, isMissingTableError catches the
Prisma P2021 and logs a warning rather than crashing the admin panel — the same
safe-degradation pattern used for permissions.
Related
How is this guide?
Last updated on