Description
Operating System
Windows 10
Environment (if applicable)
Chrome Versión 135.0.7049.96 (Build oficial) (64 bits), node -v v22.14.0, Nuxt 3
Firebase SDK Version
firebase": "^10.13.1",
Firebase SDK Product(s)
Auth
Project Tooling
Nuxt.js 3 app using Vite, deployed on Firebase Hosting.
Detailed Problem Description
Description:
We are encountering a persistent issue with Firebase Phone Authentication (signInWithPhoneNumber
) in our Nuxt.js web application hosted on Firebase Hosting (rdmercana.web.app
).
Expected behavior:
Successfully send SMS verification codes to real phone numbers using signInWithPhoneNumber
.
Actual behavior:
When attempting to send a verification code to any real phone number, the process fails immediately. We observe the following errors:
- In the web application UI/console:
FirebaseError: Error (auth/error-code:-39)
- In the browser's network tab: A
POST
request tohttps://identitytoolkit.googleapis.com/v1/accounts:sendVerificationCode?key=...
fails with a503 (Service Unavailable)
status code.
Importantly, this issue does not occur when using the test phone numbers configured within the Firebase Authentication settings. Test numbers work correctly.
Our Firebase project is on the Blaze (Pay-as-you-go) plan.
Troubleshooting Steps Taken:
- Verified that the Identity Platform API is enabled in the linked Google Cloud project.
- Verified that the web app's domain (
rdmercana.web.app
) andlocalhost
are included in the Authorized Domains list in Firebase Auth settings. - Verified the API Key restrictions in Google Cloud Console:
- HTTP referrers include
rdmercana.web.app/*
and relevantlocalhost
entries. - API restrictions allow the Identity Platform API (or keys are unrestricted).
- HTTP referrers include
- Verified the Firebase configuration details (
apiKey
,authDomain
,projectId
) in our Nuxt.js application are correct. - Disabled reCAPTCHA Account Defender in the Google Cloud Console (the issue persisted).
- Confirmed test phone numbers work correctly.
- Waited over 24 hours to allow potential temporary anti-abuse blocks or rate limits to expire, but the issue persists for real numbers.
Hypothesis:
Given that test numbers function correctly and we are on the Blaze plan, the issue seems related to Firebase's anti-abuse or security mechanisms specifically affecting SMS delivery to real numbers for our project. It might be a persistent block or limit that hasn't cleared automatically, as suggested in similar issues like firebase/flutterfire#3817.
We require assistance in diagnosing why real numbers are consistently failing with auth/error-code:-39
/ 503
despite the correct configuration and Blaze plan status. Is there a way to investigate potential blocks or gain more insight into the specific reason for the failure?
Steps to reproduce:
- Set up Firebase Phone Authentication in a web project (using Firebase JS SDK v[ "^10.13.1",]).
- Ensure the project is on the Blaze plan, Identity Platform API is enabled, the domain is authorized, and API key restrictions are correctly configured (allow Identity Platform and HTTP referrers). Ensure Account Defender is disabled.
- Use a component similar to the one described below to implement the phone sign-in flow using
signInWithPhoneNumber
and an invisibleRecaptchaVerifier
. - Deploy the application (e.g., to Firebase Hosting).
- Attempt to sign in using a configured test phone number: Enter the test number and trigger the
signInWithPhoneNumber
function.- Expected: The invisible reCAPTCHA should pass, and the function should resolve successfully, proceeding to the code verification step.
- Actual: This works correctly as expected.
- Attempt to sign in using a real phone number (e.g., +1829xxxxxxx): Enter a valid, real phone number and trigger the
signInWithPhoneNumber
function.- Expected: The invisible reCAPTCHA should pass, the SMS code should be sent, and the function should resolve successfully.
- Actual: The
signInWithPhoneNumber
function fails almost immediately. The browser console showsFirebaseError: Error (auth/error-code:-39)
, and the network request toidentitytoolkit.googleapis.com/.../accounts:sendVerificationCode
shows a503 Service Unavailable
error. This happens consistently for real numbers despite waiting periods.
Relevant Code Snippet (Simplified Logic from our LoginPhone.vue
):
```javascript
import { RecaptchaVerifier, signInWithPhoneNumber } from 'firebase/auth';
// ... other imports and setup ...
const auth = getAuth(); // Assuming $auth is initialized getAuth() result
const phoneNumber = ref('+1...'); // User input for real phone number
const recaptchaVerifier = ref(null);
const confirmationResult = ref(null);
const loading = ref(false);
const errorMessage = ref('');
onMounted(() => {
recaptchaVerifier.value = new RecaptchaVerifier(auth, 'recaptcha-container', {
size: 'invisible',
callback: (response) => { console.log('reCAPTCHA verified'); },
'expired-callback': () => { errorMessage.value = 'reCAPTCHA expired'; }
});
recaptchaVerifier.value.render().catch(err => console.error("Recaptcha render error:", err));
});
async function sendVerificationCode() {
loading.value = true;
errorMessage.value = '';
try {
// This is the call that fails for REAL numbers with error -39 / 503
confirmationResult.value = await signInWithPhoneNumber(auth, phoneNumber.value, recaptchaVerifier.value);
// Proceeds to verification step (only reached for test numbers)
console.log('Confirmation result received:', confirmationResult.value);
} catch (error) {
console.error('Error sending verification code:', error); // Logs the auth/error-code:-39
errorMessage.value = `Error: ${error.message}`;
} finally {
loading.value = false;
}
}
// Template would include an input for phoneNumber, a button calling sendVerificationCode,
// and the
```
Relevant Log Output:
```log
Enviando código de verificación SMS...
POST https://identitytoolkit.googleapis.com/v1/accounts:sendVerificationCode?key=[] 503 (Service Unavailable)
Error durante el proceso de envío de código: FirebaseError: Firebase: Error (auth/error-code:-39).
at hd (...)
at wn (...)
at Tw (...)
at async kO (...)
at async jU (...)
at async E (...)
reCAPTCHA v2 (Firebase Auth) reseteado.
```
Steps and code to reproduce issue
Steps to reproduce:
- Set up Firebase Phone Authentication in a web project (using Firebase JS SDK v["^10.13.1",]).
- Ensure the project is on the Blaze plan, Identity Platform API is enabled, the domain is authorized, and API key restrictions are correctly configured (allow Identity Platform and HTTP referrers). Ensure Account Defender is disabled.
- Use a component similar to the one described below to implement the phone sign-in flow using
signInWithPhoneNumber
and an invisibleRecaptchaVerifier
. - Deploy the application (e.g., to Firebase Hosting).
- Attempt to sign in using a configured test phone number: Enter the test number and trigger the
signInWithPhoneNumber
function.- Expected: The invisible reCAPTCHA should pass, and the function should resolve successfully, proceeding to the code verification step.
- Actual: This works correctly as expected.
- Attempt to sign in using a real phone number (e.g., +1829xxxxxxx): Enter a valid, real phone number and trigger the
signInWithPhoneNumber
function.- Expected: The invisible reCAPTCHA should pass, the SMS code should be sent, and the function should resolve successfully.
- Actual: The
signInWithPhoneNumber
function fails almost immediately. The browser console showsFirebaseError: Error (auth/error-code:-39)
, and the network request toidentitytoolkit.googleapis.com/.../accounts:sendVerificationCode
shows a503 Service Unavailable
error. This happens consistently for real numbers despite waiting periods.
Relevant Code Snippet (Simplified Logic from our LoginPhone.vue
):
```javascript
import { RecaptchaVerifier, signInWithPhoneNumber } from 'firebase/auth';
// ... other imports and setup ...
const auth = getAuth(); // Assuming $auth is initialized getAuth() result
const phoneNumber = ref('+1...'); // User input for real phone number
const recaptchaVerifier = ref(null);
const confirmationResult = ref(null);
const loading = ref(false);
const errorMessage = ref('');
onMounted(() => {
recaptchaVerifier.value = new RecaptchaVerifier(auth, 'recaptcha-container', {
size: 'invisible',
callback: (response) => { console.log('reCAPTCHA verified'); },
'expired-callback': () => { errorMessage.value = 'reCAPTCHA expired'; }
});
recaptchaVerifier.value.render().catch(err => console.error("Recaptcha render error:", err));
});
async function sendVerificationCode() {
loading.value = true;
errorMessage.value = '';
try {
// This is the call that fails for REAL numbers with error -39 / 503
confirmationResult.value = await signInWithPhoneNumber(auth, phoneNumber.value, recaptchaVerifier.value);
// Proceeds to verification step (only reached for test numbers)
console.log('Confirmation result received:', confirmationResult.value);
} catch (error) {
console.error('Error sending verification code:', error); // Logs the auth/error-code:-39
errorMessage.value = `Error: ${error.message}`;
} finally {
loading.value = false;
}
}
// Template would include an input for phoneNumber, a button calling sendVerificationCode,
// and the
```