Phone Auth Reset โ Dev Testing Guide โ
Last Updated: 2026-03-18
Instructions for resetting phone authentication state on a real dev Firebase project (lantern-app-dev) so you can re-test phone signup/login flows without creating a new account.
Scope: These commands hit the live dev project, not emulators. For emulator-based testing see FIREBASE_EMULATOR_TESTING.md.
Quick Script โ
A single script runs all the steps below (inspect โ remove phone provider โ reset Firestore):
# Full reset
./tooling/scripts/reset-phone-auth.sh <USER_UID>
# Inspect only (no changes)
./tooling/scripts/reset-phone-auth.sh <USER_UID> --inspect-onlyPrerequisites โ
- Node.js 22+
firebase-admininstalled (available in the repo's rootnode_modules)- Correct
GOOGLE_APPLICATION_CREDENTIALSor Application Default Credentials forlantern-app-dev - The target user's UID (find it in Firebase Console โ Authentication)
1. Remove the Phone Provider from Firebase Auth โ
Strips the phone provider so the user can re-link or re-test phone signup:
cd /home/mechelle/repos/lantern_app && node -e "
const admin = require('firebase-admin');
const app = admin.initializeApp({ projectId: 'lantern-app-dev' });
const UID = '<USER_UID>';
admin.auth().updateUser(UID, { phoneNumber: null })
.then(() => console.log('Phone provider removed successfully'))
.catch(err => console.error('Error:', err.message))
.finally(() => app.delete());
"Replace <USER_UID> with the target user's UID.
2. Inspect the User Document โ
Check which phone/encryption fields are currently set:
cd /home/mechelle/repos/lantern_app && node -e "
const admin = require('firebase-admin');
const app = admin.apps.length ? admin.app() : admin.initializeApp({ projectId: 'lantern-app-dev' });
const db = admin.firestore();
const UID = '<USER_UID>';
db.collection('users').doc(UID).get()
.then(snap => {
const d = snap.data();
console.log(JSON.stringify({
salt: d.salt || null,
phoneSalt: d.phoneSalt || null,
phone: d.phone || null,
authProofHash: d.authProofHash ? '(present)' : null,
encryptedSeed: d.encryptedSeed ? '(present)' : null,
recoveryPhraseHash: d.recoveryPhraseHash ? '(present)' : null,
authMethod: d.authMethod || null,
lanternName: d.lanternName || null,
}, null, 2));
})
.catch(e => console.error(e.message))
.finally(() => app.delete());
"3. Full Reset โ Revert to Passphrase-Based Login โ
Removes all phone+PIN migration fields, generates a new salt, and clears encrypted data that was keyed to the old phone+PIN (now unreadable):
cd /home/mechelle/repos/lantern_app && node -e "
const admin = require('firebase-admin');
const crypto = require('crypto');
const app = admin.apps.length ? admin.app() : admin.initializeApp({ projectId: 'lantern-app-dev' });
const db = admin.firestore();
const UID = '<USER_UID>';
const userRef = db.collection('users').doc(UID);
(async () => {
const newSalt = crypto.randomBytes(16).toString('base64');
await userRef.update({
// Restore passphrase-based login
salt: newSalt,
// Remove phone+PIN migration fields
phone: admin.firestore.FieldValue.delete(),
phoneSalt: admin.firestore.FieldValue.delete(),
encryptedSeed: admin.firestore.FieldValue.delete(),
authProofHash: admin.firestore.FieldValue.delete(),
recoveryPhraseHash: admin.firestore.FieldValue.delete(),
encryptionMigratedAt: admin.firestore.FieldValue.delete(),
// Clear encrypted fields (keyed to old phone+PIN, now unreadable)
encryptedBirthDate: admin.firestore.FieldValue.delete(),
encryptionCanary: admin.firestore.FieldValue.delete(),
encryptionCorrupted: admin.firestore.FieldValue.delete(),
encryptionCorruptedDetectedAt: admin.firestore.FieldValue.delete(),
});
console.log('Done. Account reset to passphrase-based login.');
console.log('New salt:', newSalt);
const snap = await userRef.get();
const d = snap.data();
console.log('Verify:', JSON.stringify({
salt: d.salt ? '(present)' : null,
phoneSalt: d.phoneSalt || null,
phone: d.phone || null,
role: d.role || null,
lanternName: d.lanternName || null,
}, null, 2));
await app.delete();
})();
"Important: After this reset the user must set a new passphrase on next login. Any data encrypted with the old phone+PIN key is permanently lost (by design โ zero-knowledge encryption).
4. Verify Encrypted Fields Were Cleared โ
Quick spot-check that stale encrypted data was removed:
cd /home/mechelle/repos/lantern_app && node -e "
const admin = require('firebase-admin');
const app = admin.apps.length ? admin.app() : admin.initializeApp({ projectId: 'lantern-app-dev' });
const db = admin.firestore();
const UID = '<USER_UID>';
db.collection('users').doc(UID).get().then(snap => {
const d = snap.data();
console.log('encryptedBirthDate:', d.encryptedBirthDate || '(not present)');
console.log('encryptionCanary:', d.encryptionCanary || '(not present)');
app.delete();
});
"5. Re-Encrypt Birthday via Browser Console โ
After logging back in (so the encryption key is cached in memory), you can re-encrypt and save the birthday from the browser console:
const encryption = await import('/src/lib/encryption.js');
const firebase = await import('/src/firebase.js');
const encrypted = await encryption.encryptData('1989-09-30'); // use actual birth date
const uid = firebase.auth.currentUser.uid;
const token = await firebase.auth.currentUser.getIdToken();
await fetch(
`https://firestore.googleapis.com/v1/projects/lantern-app-dev/databases/(default)/documents/users/${uid}?updateMask.fieldPaths=encryptedBirthDate`,
{
method: 'PATCH',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
fields: { encryptedBirthDate: { stringValue: encrypted } },
}),
}
);
console.log('Birthday saved');Run this in the DevTools console on the running Lantern app (must be logged in so the encryption key is available).
Typical Reset Workflow โ
- Remove phone provider (Step 1)
- Full reset to passphrase (Step 3)
- Verify fields cleared (Step 4)
- Log in with the new passphrase flow
- Re-encrypt birthday in browser console (Step 5)
See Also โ
- FIREBASE_EMULATOR_TESTING.md โ Phone+PIN flows in the emulator (no live data)
- LOCAL_TESTING.md โ General local dev testing
apps/web/src/lib/encryption.jsโ Zero-knowledge encryption module