Firebase Rate Limit & Auth Errors: Fix 401, 403, 429, 502, 503, Token Expired
Fix Firebase rate limit, 401 unauthorized, 403 forbidden, 502/503 errors, and token expiration with step-by-step diagnostic commands and proven solutions.
- Firebase 401/unauthorized errors almost always mean an expired or malformed ID token — refresh it before every request using getIdToken(true)
- Rate limiting (HTTP 429) triggers when you exceed Firestore read/write quotas or Authentication sign-in limits; use exponential backoff and batch writes to stay under quota
- 502 and 503 responses are Firebase infrastructure transients — implement retry logic with jitter; persistent 503s on Cloud Functions indicate cold-start timeouts or memory limits
- Firebase 403 (permission denied) is a security rules mismatch, not an auth failure — test rules in the Firebase Rules Playground before deploying
- Invalid or expired tokens are the root cause of 60%+ of Firebase auth failures; always validate token expiry client-side before making API calls
| Method | When to Use | Time to Implement | Risk |
|---|---|---|---|
| Force token refresh (getIdToken(true)) | 401 on valid user session, token > 55 min old | 5 minutes | Low — safe idempotent call |
| Exponential backoff with jitter | 429 rate limit, 503 service unavailable | 30 minutes | Low — standard retry pattern |
| Rewrite Firestore Security Rules | 403 permission denied on valid auth | 15–60 minutes | Medium — can lock out users if wrong |
| Batch writes / transactions | Hitting Firestore write quota (20k/min) | 1–4 hours | Low — improves throughput and atomicity |
| Increase Cloud Function timeout/memory | 503 on Functions, connection refused | 10 minutes | Low — increases cost slightly |
| Upgrade Firebase plan (Spark → Blaze) | Persistent quota exhaustion on free tier | 5 minutes | Low — pay-as-you-go billing starts |
| Firebase App Check enforcement | 401 from unauthenticated app abuse | 2–8 hours | Medium — requires client SDK update |
| Regional endpoint selection | Persistent 502 latency spikes | 20 minutes | Low — transparent to end users |
Understanding Firebase Rate Limit and Auth Errors
Firebase surfaces errors across two distinct layers: the Authentication service (identity tokens, sign-in methods) and the backend services (Firestore, Realtime Database, Cloud Functions, Storage). Each layer has its own quota system, and a failure in one often cascades into errors that look like auth problems in another.
The most common error messages developers encounter:
FirebaseError: Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. Got 'null'.
FirebaseError: PERMISSION_DENIED: Missing or insufficient permissions.
POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword 400
FirebaseError: TOO_MANY_REQUESTS
[auth/network-request-failed] A network error occurred
HTTP 401 Unauthorized
HTTP 403 Forbidden
HTTP 429 Too Many Requests
HTTP 502 Bad Gateway
HTTP 503 Service Unavailable
Step 1: Identify the Error Layer
Before fixing anything, determine whether the error originates from Firebase Authentication or a downstream service (Firestore, Functions, Storage).
Check the Firebase Authentication service status:
https://status.firebase.google.com
In your browser console or server logs, look at the full request URL in the failed response:
identitytoolkit.googleapis.com→ Authentication layerfirestore.googleapis.com→ Firestorecloudfunctions.netorrun.app→ Cloud Functionsstorage.googleapis.com→ Firebase Storage
Extract the error code programmatically:
try {
await signInWithEmailAndPassword(auth, email, password);
} catch (error) {
console.error('Code:', error.code); // e.g. 'auth/too-many-requests'
console.error('Message:', error.message); // Human-readable
}
Common error.code values and their root causes:
| Code | Meaning |
|---|---|
auth/id-token-expired |
Token older than 1 hour, needs refresh |
auth/invalid-id-token |
Token malformed or from wrong project |
auth/too-many-requests |
IP or account temporarily blocked |
auth/network-request-failed |
DNS/TLS failure or Firebase outage |
auth/unauthorized-domain |
App domain not whitelisted in Firebase console |
permission-denied |
Security rules rejected the request |
Step 2: Fix Token Expiration (401 / auth/id-token-expired)
Firebase ID tokens expire after 60 minutes. The Firebase SDK auto-refreshes them — but only if you use onAuthStateChanged correctly. Calling getIdToken() without the forceRefresh flag returns the cached (possibly expired) token.
Wrong approach (uses stale token):
const token = await user.getIdToken(); // May return expired token from cache
Correct approach:
// Force refresh when token is near expiry
const token = await user.getIdToken(true); // Forces network call to refresh
// Better: use an Axios interceptor to auto-refresh on 401
axios.interceptors.response.use(
response => response,
async error => {
if (error.response?.status === 401) {
const user = auth.currentUser;
if (user) {
const freshToken = await user.getIdToken(true);
error.config.headers['Authorization'] = `Bearer ${freshToken}`;
return axios(error.config); // Retry with new token
}
}
return Promise.reject(error);
}
);
Server-side token verification (Node.js Admin SDK):
const admin = require('firebase-admin');
async function verifyToken(idToken) {
try {
const decoded = await admin.auth().verifyIdToken(idToken);
return decoded;
} catch (error) {
if (error.code === 'auth/id-token-expired') {
// Token expired — client must refresh
throw new Error('TOKEN_EXPIRED');
}
if (error.code === 'auth/argument-error') {
// Malformed token — do not retry
throw new Error('INVALID_TOKEN');
}
throw error;
}
}
Step 3: Fix Rate Limiting (429 / TOO_MANY_REQUESTS)
Firebase enforces rate limits at multiple levels:
- Authentication: 100 sign-up/sign-in requests per IP per minute (adjustable in console)
- Firestore: 1 write per second per document; 10,000 writes per second per database on Blaze plan
- Cloud Functions: 3,000 concurrent executions on Blaze; automatic scale-up with cold start latency
Implement exponential backoff with jitter:
async function withRetry(fn, maxRetries = 5) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
const isRateLimit =
error.code === 'resource-exhausted' ||
error.status === 429 ||
error.message?.includes('TOO_MANY_REQUESTS');
if (!isRateLimit || attempt === maxRetries) throw error;
// Exponential backoff: 1s, 2s, 4s, 8s, 16s + jitter
const base = Math.pow(2, attempt) * 1000;
const jitter = Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, base + jitter));
}
}
}
// Usage
await withRetry(() => setDoc(doc(db, 'users', uid), data));
Use Firestore batch writes to reduce operation count:
const batch = writeBatch(db);
users.forEach(user => {
const ref = doc(db, 'users', user.id);
batch.set(ref, user); // Counts as 1 write regardless of batch size
});
await batch.commit(); // Single network round-trip, up to 500 docs
Step 4: Fix Permission Denied (403 / PERMISSION_DENIED)
A 403 means your Security Rules rejected the request. This is not the same as being unauthenticated — a logged-in user can still receive 403 if rules don't allow the operation.
Test rules without deploying using the Rules Playground:
- Firebase Console → Firestore → Rules → Rules Playground
- Set Auth UID to your test user's UID
- Simulate the exact read/write path
Common Firestore rules mistakes:
// BAD: Allows read but denies write — often confused with auth error
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth != null;
// Missing write rule defaults to DENY
}
}
}
// GOOD: Explicit rules with ownership check
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth != null;
allow write: if request.auth != null && request.auth.uid == userId;
}
}
}
Validate rules with the Firebase CLI:
npm install -g firebase-tools
firebase login
# Test rules locally before deploying
firebase emulators:start --only firestore
# Deploy rules
firebase deploy --only firestore:rules
Step 5: Fix 502 / 503 / Connection Refused
HTTP 502 (Bad Gateway) and 503 (Service Unavailable) from Firebase are almost always transient infrastructure issues or Cloud Functions problems.
For Cloud Functions 503 / connection refused:
# Check function logs for timeout or memory errors
firebase functions:log --only myFunction
# Increase timeout and memory in function definition
exports.myFunction = functions
.runWith({ timeoutSeconds: 300, memory: '512MB' })
.https.onRequest(async (req, res) => {
// ...
});
Reduce cold start latency with minimum instances:
exports.criticalApi = functions
.runWith({ minInstances: 1 }) // Keeps 1 instance warm
.https.onRequest(handler);
Test connectivity to Firebase endpoints:
curl -I https://firestore.googleapis.com
curl -I https://identitytoolkit.googleapis.com
nslookup firestore.googleapis.com
Frequently Asked Questions
#!/usr/bin/env bash
# Firebase Diagnostic Script
# Run this to collect evidence before filing a support ticket
set -euo pipefail
PROJECT_ID="${FIREBASE_PROJECT_ID:-your-project-id}"
echo "=== Firebase Connectivity Check ==="
curl -s -o /dev/null -w "identitytoolkit: %{http_code}\n" \
https://identitytoolkit.googleapis.com
curl -s -o /dev/null -w "firestore: %{http_code}\n" \
https://firestore.googleapis.com
curl -s -o /dev/null -w "firebase status page: %{http_code}\n" \
https://status.firebase.google.com
echo ""
echo "=== DNS Resolution ==="
nslookup firestore.googleapis.com | grep -E 'Address|Name'
nslookup identitytoolkit.googleapis.com | grep -E 'Address|Name'
echo ""
echo "=== Firebase CLI Auth Status ==="
firebase login:list 2>/dev/null || echo "firebase-tools not installed or not logged in"
echo ""
echo "=== Project Quota (requires gcloud) ==="
if command -v gcloud &>/dev/null; then
gcloud auth application-default print-access-token &>/dev/null && \
gcloud services quota list \
--service=firestore.googleapis.com \
--project="$PROJECT_ID" \
--format="table(metric, currentUsage, limit)" 2>/dev/null || \
echo "Run: gcloud auth application-default login"
fi
echo ""
echo "=== Recent Cloud Functions Errors ==="
if command -v firebase &>/dev/null; then
firebase functions:log \
--project="$PROJECT_ID" \
--lines=50 2>/dev/null | \
grep -iE 'error|exception|rate.limit|quota|timeout|503|502|401|403' || \
echo "No matching error lines found"
fi
echo ""
echo "=== Test Token Verification (Node.js) ==="
cat <<'EOF'
// Save as check-token.js and run: node check-token.js <idToken>
const admin = require('firebase-admin');
admin.initializeApp(); // Uses GOOGLE_APPLICATION_CREDENTIALS env var
const token = process.argv[2];
if (!token) { console.error('Usage: node check-token.js <idToken>'); process.exit(1); }
admin.auth().verifyIdToken(token)
.then(decoded => {
const expiresIn = decoded.exp - Math.floor(Date.now() / 1000);
console.log('Token valid. UID:', decoded.uid);
console.log('Expires in:', expiresIn, 'seconds');
console.log('Issued at:', new Date(decoded.iat * 1000).toISOString());
console.log('Claims:', JSON.stringify(decoded, null, 2));
})
.catch(err => {
console.error('Token verification FAILED');
console.error('Code:', err.code);
console.error('Message:', err.message);
});
EOF
echo ""
echo "=== Firestore Rules Emulator Test ==="
cat <<'EOF'
# Install and start the emulator
npm install -g firebase-tools
firebase emulators:start --only firestore --project demo-test
# In another terminal, test rules with the REST API
curl -X POST \
'http://localhost:8080/v1/projects/demo-test/databases/(default)/documents/users' \
-H 'Authorization: Bearer owner' \
-H 'Content-Type: application/json' \
-d '{"fields": {"name": {"stringValue": "test"}}}'
EOF
echo ""
echo "Diagnostic complete. Check output above for anomalies."Error Medic Editorial
Error Medic Editorial is a team of senior DevOps and SRE engineers with combined experience across Google Cloud, Firebase, AWS, and Azure. We specialize in production incident postmortems, quota management, and distributed systems reliability. Our guides are tested against real production workloads before publication.
Sources
- https://firebase.google.com/docs/auth/admin/errors
- https://firebase.google.com/docs/firestore/quotas
- https://firebase.google.com/docs/functions/manage-functions
- https://cloud.google.com/firestore/docs/best-practices
- https://stackoverflow.com/questions/38233003/firebase-auth-idtoken-expires-in-one-hour
- https://github.com/firebase/firebase-js-sdk/issues/1446
- https://firebase.google.com/docs/rules/simulator