Skip to content

Firebase Emulator Testing โ€” Phone+PIN Flows โ€‹

Last Updated: 2026-03-17

Guide for testing Phone+PIN authentication, email encryption, phone recycling, and recovery backup flows using the Firebase Emulator Suite.


Prerequisites โ€‹

  • Node.js 22+
  • Firebase CLI installed (npm install -g firebase-tools)
  • .env.local configured (copy from .env.local.example)

1. Setup โ€‹

Enable Emulator Connections โ€‹

Add to your .env.local:

bash
VITE_USE_EMULATORS=true

This tells the frontend to connect to local emulators instead of the real Firebase project. Remove or clear this value when you want to use the real backend.

Emulator Secrets โ€‹

Cloud Functions that use secrets (email encryption, Resend API) need a .secret.local file in the functions directory:

bash
# services/functions/firebase/.secret.local
RESEND_API_KEY=re_test_fake_key_for_emulator
EMAIL_ENCRYPTION_KEY=<any-64-char-hex-string>

Generate a test encryption key:

bash
python3 -c "import secrets; print(secrets.token_hex(32))"

Note: .secret.local is gitignored and must never be committed.


2. Starting the Emulators โ€‹

Quick Start โ€‹

bash
npm run emulators        # Kills stale ports, starts auth + functions + firestore

Individual Commands โ€‹

bash
npm run emulators:kill   # Kill processes on emulator ports only
npm run emulators:firestore  # Start firestore emulator only

Emulator Ports โ€‹

ServicePortURL
Auth9099http://127.0.0.1:9099
Functions5001http://127.0.0.1:5001
Firestore8080http://127.0.0.1:8080
Emulator UI4000http://127.0.0.1:4000
Hub4400http://127.0.0.1:4400

Start the Dev Server โ€‹

In a second terminal:

bash
npm run dev

Open http://localhost:5173. You should see ๐Ÿ”ง Firebase Emulators connected in the browser console.


3. Testing Phone+PIN Signup โ€‹

Navigate to http://localhost:5173/#/signup/phone

Step 1 โ€” Phone Number + Age โ€‹

  • Enter a phone number (e.g., 555-123-4567)
  • Check the age verification box
  • Click "Continue"

Step 2 โ€” PIN Creation โ€‹

  • Enter a 6-digit PIN (avoid weak PINs like 123456, 000000)
  • Confirm the PIN
  • All three checks must show green: 6 digits, not common, PINs match
  • Click "Continue"

Step 3 โ€” Email Capture (Optional) โ€‹

  • Enter an email address twice (must match)
  • Or click "Skip for now"
  • If provided, the encryptUserEmail Cloud Function runs on the emulator

Step 4 โ€” Recovery Phrase โ€‹

  • A 12-word BIP39 recovery phrase is displayed
  • Copy it down โ€” this is the only way to recover the account if the PIN is forgotten
  • Optionally click "Email encrypted backup" to test the backup flow
  • Check the confirmation checkbox
  • Click "Continue"

Step 5 โ€” Terms โ€‹

  • Accept terms to complete signup
  • Account is created in the Auth emulator, profile written to Firestore emulator

Verification โ€‹

Open the Emulator UI at http://127.0.0.1:4000:

  • Auth tab: New user appears with the email used during signup
  • Firestore tab โ†’ users collection: Profile document with fields:
    • phone โ€” normalized phone number
    • phoneSalt, encryptedSeed, recoveryPhraseHash โ€” encryption data
    • lanternName โ€” generated display name
    • authMethod: "phone_pin"
    • encryptedEmail (if email was provided and Cloud Function succeeded)

4. Testing Phone+PIN Login โ€‹

Navigate to http://localhost:5173/#/login/phone

  • Enter the same phone number from signup
  • Enter the 6-digit PIN
  • Should unlock encryption and log you in

PIN Lockout โ€‹

  • Enter wrong PINs 3+ times
  • A countdown lockout timer appears
  • After lockout, "Reclaim this number" link appears (tests the reclaim flow)

5. Testing Phone Reclaim Flow โ€‹

The reclaim flow handles phone number recycling (someone gets a previously-used phone number).

  1. At the Phone+PIN login screen, fail 3+ PIN attempts
  2. Click "Reclaim this number"
  3. A modal appears with the reclaim flow:
    • Confirm step: Explains the 48-hour grace period
    • Waiting step: Polls checkPhoneReclaimStatus every 30 seconds
    • Complete step: Calls completePhoneReclaim to transfer the number

Emulator Verification โ€‹

  • Firestore โ†’ phoneReclaims collection: New reclaim document with status and timestamps
  • Functions logs (in emulator terminal): initiatePhoneReclaim, checkPhoneReclaimStatus, completePhoneReclaim invocations

6. Testing Email Encrypted Backup โ€‹

During signup step 4 (Recovery Phrase):

  1. Click "Email encrypted backup"
  2. Enter a backup password (8+ chars, must contain a letter and a number)
  3. Click "Encrypt & Send"
  4. The backup is encrypted client-side (PBKDF2 + AES-GCM), then sent via sendRecoveryBackupEmail

Note: Emails won't actually send in the emulator (Resend API key is fake), but the Cloud Function executes and logs the attempt. Check the functions emulator output for confirmation.


7. Monitoring & Debugging โ€‹

Emulator UI โ€‹

Open http://127.0.0.1:4000 to:

  • Auth tab โ€” View/manage created users, reset passwords
  • Firestore tab โ€” Browse collections (users, phoneReclaims), inspect documents
  • Functions logs โ€” See Cloud Function executions, errors, and devLog output

Browser Console โ€‹

Look for these indicators:

LogMeaning
๐Ÿ”ง Firebase Emulators connectedFrontend is using emulators
โœ… Signup complete: {...}Account creation succeeded
Failed to encrypt email server-side (non-fatal)encryptUserEmail failed (check .secret.local)
User profile not foundRace condition during signup (harmless, resolves on reload)

Known Emulator Behaviors โ€‹

  • Profile not found on first load โ€” createUserWithEmailAndPassword fires onAuthStateChanged before setDoc writes the profile. This is a harmless race condition. The profile loads correctly after reload.
  • Flash analytics 401s โ€” The analytics API isn't part of the emulator suite. Token validation fails for emulator users. Not an issue.
  • enableIndexedDbPersistence deprecation warning โ€” Firebase SDK warning, safe to ignore.

8. Cleanup โ€‹

Stop Emulators โ€‹

Ctrl+C in the emulator terminal, or:

bash
npm run emulators:kill

Reset Emulator Data โ€‹

Emulator data is ephemeral by default โ€” stopping and restarting clears all Auth users and Firestore documents.

Disable Emulator Connections โ€‹

In .env.local, remove or clear the emulator flag:

bash
VITE_USE_EMULATORS=

Then restart the dev server.


See Also โ€‹

Built with VitePress