This Firebase Authentication error occurs when the continue URL provided for email actions (password reset, email verification) is invalid, malformed, or not authorized. The continue URL must be a properly formatted URL with an authorized domain that matches your Firebase project configuration.
The "auth/invalid-continue-uri" error is a Firebase Authentication error that occurs when you provide a continue URL for email actions (password reset, email verification, email change) that Firebase cannot accept. This error is more specific than the "missing-continue-uri" error - it means you HAVE provided a continue URL, but Firebase has determined it's invalid. Common reasons include: 1. **Malformed URL**: The URL doesn't follow proper URL syntax (missing protocol, invalid characters, etc.) 2. **Unauthorized domain**: The domain in the URL is not listed in your Firebase project's authorized domains 3. **Invalid protocol**: Using http:// in a production environment that requires https:// 4. **Localhost in production**: Using localhost URLs in a production Firebase project 5. **URL contains fragments**: URLs with #hash fragments are not allowed 6. **Dynamic link misconfiguration**: For mobile apps, the dynamic link domain isn't properly configured The continue URL is critical because it's where users are redirected after completing email actions. Firebase validates this URL strictly for security reasons to prevent phishing attacks and ensure users return to your legitimate application.
First, ensure your continue URL follows Firebase's URL requirements:
// ✅ Valid URL formats
'https://yourapp.com/reset-password-complete'
'https://yourapp.com/verify-email?userId=123'
'http://localhost:3000/auth-callback' // Only for development
'https://yourapp.page.link/reset' // For Firebase Dynamic Links
// ❌ Invalid URL formats
'/reset-password' // Missing protocol and domain
'yourapp.com/reset-password' // Missing protocol
'https://yourapp.com/#/reset' // Contains fragment (#)
'http://yourapp.com/reset' // HTTP in production (needs HTTPS)
'https://unauthorized.com/reset' // Domain not authorized
'https://sub.yourapp.com/reset' // Subdomain not authorized if only root domain isKey requirements:
1. Must start with http:// or https://
2. Domain must be authorized in Firebase Console
3. No #fragment identifiers allowed
4. HTTPS required for production environments
5. Localhost only allowed in development
Your continue URL's domain MUST be in the authorized domains list:
1. Go to Firebase Console (console.firebase.google.com)
2. Select your project
3. Navigate to Authentication → Settings
4. Under "Authorized domains", check if your domain is listed:
Authorized domains should include:
- yourapp.com # Your production domain
- localhost # For development
- yourapp.page.link # For Firebase Dynamic Links (if used)5. If your domain is missing, click "Add domain" and enter it
6. For subdomains: If using sub.yourapp.com, you may need to add the specific subdomain or configure wildcard authorization
7. Save changes and wait a few minutes for propagation
Note: Changes to authorized domains may take a few minutes to propagate through Firebase's systems.
Firebase has strict requirements about HTTP vs HTTPS:
// Development environment (localhost)
const devActionCodeSettings = {
url: 'http://localhost:3000/reset-complete', // HTTP OK for localhost
handleCodeInApp: false
};
// Production environment
const prodActionCodeSettings = {
url: 'https://yourapp.com/reset-complete', // MUST use HTTPS
handleCodeInApp: false
};
// Dynamic configuration based on environment
const actionCodeSettings = {
url: process.env.NODE_ENV === 'development'
? 'http://localhost:3000/reset-complete'
: 'https://yourapp.com/reset-complete',
handleCodeInApp: false
};Important rules:
- Production: Always use https://
- Localhost development: http:// is acceptable
- Custom domains: Must support HTTPS with valid SSL certificate
- Firebase Hosting: Automatically provides HTTPS
If you're getting this error in production, ensure your URL starts with https:// and your domain has a valid SSL certificate.
For mobile apps using deep links, you need Firebase Dynamic Links:
// Mobile app configuration
const actionCodeSettings = {
url: 'https://yourapp.page.link/reset', // Dynamic Link URL
handleCodeInApp: true, // Important: true for mobile apps
dynamicLinkDomain: 'yourapp.page.link', // Your Dynamic Link domain
// iOS configuration
ios: {
bundleId: 'com.yourapp.ios',
// appStoreId: '123456789', // Optional App Store ID
// minimumVersion: '12.0', // Optional minimum version
},
// Android configuration
android: {
packageName: 'com.yourapp.android',
installApp: true, // Prompt to install if not installed
minimumVersion: '12', // Minimum app version
},
};
// Send password reset with Dynamic Links
sendPasswordResetEmail(auth, email, actionCodeSettings);Setup steps:
1. Enable Firebase Dynamic Links in your project
2. Configure your Dynamic Link domain (yourapp.page.link)
3. Add the domain to authorized domains in Firebase Console
4. Configure your mobile app to handle the deep links
5. Test with handleCodeInApp: true
Without proper Dynamic Links configuration, mobile app continue URLs will fail validation.
If your continue URL has query parameters, they must be properly encoded:
// ❌ Problematic - unencoded parameters
const badUrl = 'https://yourapp.com/[email protected]&token=abc/def';
// The '/' in token breaks URL parsing
// ✅ Properly encoded
const goodUrl = 'https://yourapp.com/reset?email=user%40example.com&token=abc%2Fdef';
// Using URLSearchParams for proper encoding
const params = new URLSearchParams({
email: '[email protected]',
token: 'abc/def',
redirect: '/dashboard'
});
const baseUrl = 'https://yourapp.com/reset-complete';
const fullUrl = `${baseUrl}?${params.toString()}`;
// Result: https://yourapp.com/reset-complete?email=user%40example.com&token=abc%2Fdef&redirect=%2Fdashboard
// Use in Firebase
const actionCodeSettings = {
url: fullUrl,
handleCodeInApp: false
};Common encoding issues:
- Special characters: @, /, ?, &, =, +, % must be encoded
- Spaces: Should be %20 or +
- Unicode characters: Must be UTF-8 encoded
- JSON in URLs: Use encodeURIComponent(JSON.stringify(data))
Test your URL by pasting it into a browser - it should load without errors.
Create a test script to validate your continue URL:
async function testContinueUrl(url) {
const auth = getAuth();
const testEmail = '[email protected]'; // Use a test email
try {
const actionCodeSettings = {
url: url,
handleCodeInApp: false
};
console.log(`Testing URL: ${url}`);
console.log(`Domain: ${new URL(url).hostname}`);
await sendPasswordResetEmail(auth, testEmail, actionCodeSettings);
console.log('✅ URL accepted by Firebase');
return { valid: true, message: 'URL accepted' };
} catch (error) {
console.error('❌ URL rejected:', error.code, error.message);
// Diagnostic information
if (error.code === 'auth/invalid-continue-uri') {
console.log('Diagnostics:');
console.log('- Check authorized domains in Firebase Console');
console.log('- Ensure URL starts with https:// (production)');
console.log('- Remove any # fragments from URL');
console.log('- Verify domain matches exactly (no www vs non-www mismatch)');
}
return { valid: false, error: error.message, code: error.code };
}
}
// Test different URLs
await testContinueUrl('https://yourapp.com/reset-complete');
await testContinueUrl('http://localhost:3000/reset-complete');
await testContinueUrl('https://yourapp.page.link/reset');This helps identify exactly which URL format Firebase accepts. Start with the simplest URL (just domain + path), then add parameters once the base URL works.
Ensure your code handles different environments correctly:
// Environment configuration
const getContinueUrl = () => {
const env = process.env.NODE_ENV || 'development';
switch (env) {
case 'production':
return 'https://yourapp.com/auth-callback';
case 'staging':
return 'https://staging.yourapp.com/auth-callback';
case 'development':
default:
return 'http://localhost:3000/auth-callback';
}
};
// Firebase configuration with environment detection
const getFirebaseConfig = () => {
// Your Firebase config - ensure you're using the right project
return {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
projectId: process.env.FIREBASE_PROJECT_ID,
// ... other config
};
};
// Common mistake: Using development Firebase config with production URLs
// or vice versa. Ensure your Firebase project matches your environment.
// Check your Firebase project ID
console.log('Current Firebase project:', firebase.app().options.projectId);
// Verify the project has your domain authorized
// Different Firebase projects = different authorized domains listsKey checks:
1. Firebase project ID matches your environment
2. Authorized domains configured for THAT specific project
3. Environment variables point to correct Firebase project
4. No mixing of development and production configurations
### Understanding Firebase's URL Validation
Firebase validates continue URLs against several criteria:
1. Domain authorization: The domain must be in the authorized domains list
2. Protocol enforcement: HTTPS required for non-localhost domains
3. URL structure: Must be a valid, absolute URL
4. Security checks: Prevents open redirect vulnerabilities
### Subdomain Handling
If you use subdomains (app.yourapp.com, admin.yourapp.com), note that:
- Adding 'yourapp.com' authorizes ALL subdomains in some Firebase configurations
- For stricter control, you may need to add each subdomain individually
- Wildcard domains (*.yourapp.com) are not supported in the Firebase Console UI
### Firebase Hosting Integration
If hosting on Firebase Hosting, your continue URLs should point to your Firebase Hosting domain:
https://your-project-id.web.app/reset-complete
https://your-project-id.firebaseapp.com/reset-complete
https://your-custom-domain.com/reset-completeThese domains are automatically authorized when you set up Firebase Hosting.
### Multiple Environment Strategy
For teams with multiple environments (dev, staging, prod):
1. Separate Firebase projects for each environment
2. Environment-specific authorized domains:
- Dev: localhost, dev.yourapp.com
- Staging: staging.yourapp.com
- Prod: yourapp.com, app.yourapp.com
3. Build-time URL configuration using environment variables
4. Consistent URL patterns across environments
### Security Implications
The strict URL validation prevents:
- Phishing attacks: Attackers can't redirect users to malicious sites
- Open redirects: Your app can't be used as an open redirector
- Domain hijacking: Ensures users return to YOUR legitimate domain
Never disable or work around these security checks. Instead, properly configure your authorized domains.
messaging/UNSPECIFIED_ERROR: No additional information available
How to fix "messaging/UNSPECIFIED_ERROR: No additional information available" in Firebase Cloud Messaging
App Check: reCAPTCHA Score Too Low
App Check reCAPTCHA Score Too Low
storage/invalid-url: Invalid URL format for Cloud Storage reference
How to fix invalid URL format in Firebase Cloud Storage
auth/missing-uid: User ID identifier required
How to fix "auth/missing-uid: User ID identifier required" in Firebase
auth/invalid-argument: Invalid parameter passed to method
How to fix "auth/invalid-argument: Invalid parameter passed to method" in Firebase