Social LiveDocumentationPLATFORM DOCS

QA Test Allowlists & Dev Overrides

Fixed OTP codes for demo and review accounts -how they work, and why they can't weaken production.

Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

TL;DR -App reviewers and QA need to log in without waiting for a real text or email. The auth service allows this only for a tiny, explicitly-named list of phone numbers and emails that get a fixed code. Blanket "make every code the same" overrides are hard-blocked in production.

Who this is for -Product & business: read "The security stance" to understand the trade-off (each allowlisted account is a known-credential account). Backend, DevOps & QA: the env vars, exact behavior per list, dev-only defaults, and the operational how-to.

When Apple or Google reviews the app, or when QA runs through a flow, they need a working account that logs in instantly -they can't receive our SMS or email. The solution is a narrow allowlist: a short, explicit list of specific phone numbers and email addresses that accept a known fixed code instead of a random one. It's never a wildcard, and it never applies to real users.

In plain terms

  • Only named accounts are affected. A phone number or email must be listed by hand. Everyone else always gets a random, hidden, one-time code.
  • Listing an account means its login code is public. Anyone who knows an allowlisted email also knows its code. So each entry is effectively a shared demo account -keep the list tiny and prune it before launch.
  • Production can't be globally weakened. The "make every code fixed" developer switches simply don't work in production. Only the per-identity allowlists do, and only for their named entries.

The security stance (read first)

Dev/test override flags (OTP_TEST_CODE, OTP_EXPOSE_CODE) are never reachable in production -no flag can override that, because a misconfigured flag would make every account's OTP a known constant. The two deliberate exceptions are identity allowlists, scoped to specific identifiers:

Anyone who knows an allowlisted identity also knows its code. Every entry is a known-credential account in production. Keep the lists tiny and prune them before public launch.

Email allowlist

These two env vars control the email allowlist:

Env varEffect
OTP_TEST_EMAILSComma-separated emails (case-insensitive) with a fixed OTP
OTP_TEST_EMAIL_CODEThe shared fixed code (default 1234)

For allowlisted emails, in all environments:

  • The OTP is the fixed code -for login/signup and email-change flows.
  • No real email is sent (provider bypassed).
  • The code is echoed back as devCode in the response (it's already public knowledge).
  • The 30-second request cooldown is skipped (nothing to spam, speeds QA).

Everything else is untouched: non-listed emails get random codes, hidden in production, throttled normally.

Phone allowlist

The phone allowlist works the same way, with one env var and slightly different mechanics:

Env varEffect
OTP_TEST_PHONE_NUMBERSComma-separated E.164 numbers

Allowlisted phones skip Twilio delivery in production and have their (random) code exposed in the response -slightly different mechanics than email, same purpose.

Dev-environment defaults (non-production only)

These blanket conveniences exist only outside production -they're the switches that are hard-blocked in prod:

  • OTP_TEST_CODE -every OTP is this fixed code (default 123456).
  • devCode is included in every OTP response.
  • OTP_ALLOW_UNSENT=true lets requests succeed with no SMS/email provider configured.

Operational notes

How to actually manage an allowlist, and how it's kept honest:

  • Preferred: manage the email allowlist with scripts/otp-test-email.sh (list / add <email> / remove <email>) -it edits .env.production, restarts the backend with the correct --env-file, and verifies the fixed-code login end-to-end.
  • Manual fallback: changing an allowlist is an env-only deploy -edit .env.production, then docker compose ... up -d backend (no image rebuild).
  • The unit suite pins the guarantees: fixed code only for listed identifiers, random+hidden for everyone else, empty list = disabled, production ignores OTP_TEST_CODE.