Firebase Phone Auth in Kotlin/Wasm: 3 Critical Console Traps
Avoid billing errors, region blocks, and reCAPTCHA pitfalls in mobile authentication flows
1Blaze plan requirement
Firebase phone authentication now mandates the Blaze pay-as-you-go plan, unlike other auth methods. Without active billing, all verification attempts fail with auth/billing-not-enabled error—including test numbers. This catches developers off guard during local testing. The restriction applies globally across all Firebase projects, requiring explicit billing setup before phone auth implementation. Developers must ensure their project's billing status before writing any authentication code to avoid runtime failures.
2SMS region policy trap
Firebase's SMS region policy denies all countries by default, throwing auth/operation-not-allowed errors. Developers must manually enable their target regions in Authentication → Settings → SMS region policy. This security measure prevents accidental international SMS charges but often gets overlooked during setup. The policy affects both production and test numbers, requiring configuration before any verification flow testing. Regional restrictions apply even when using Firebase's test phone numbers with fixed verification codes.
3Single-use reCAPTCHA tokens
Each reCAPTCHA verification token works for exactly one authentication attempt, regardless of success. Cached verifiers cause subsequent attempts to fail with auth/invalid-app-credential without clear error messaging. The solution involves creating a fresh RecaptchaVerifier instance for every verification request. This behavior differs from web implementations where verifiers might persist. The Kotlin/Wasm binding must explicitly clear and recreate verifiers between attempts to maintain reliable auth flows.
4Testing configuration specifics
Firebase provides testing switches that bypass actual SMS delivery and reCAPTCHA requirements. Developers must enable appVerificationDisabledForTesting in auth settings and register test phone numbers in the console. These test numbers use fixed verification codes (like '123456') and don't consume SMS quotas. However, the testing configuration must never ship to production—it completely disables security checks. The Kotlin/Wasm implementation includes a helper function to toggle this testing mode programmatically.
5Wasm-specific implementation challenges
The Kotlin/Wasm environment requires explicit DOM element creation for reCAPTCHA since Compose Canvas lacks native support. Developers must manually create a hidden div container for the verifier. The implementation also needs JavaScript interop for Firebase's dynamic options like invisible reCAPTCHA parameters. These Wasm-specific workarounds add complexity compared to standard Android or Kotlin/JS implementations. The solution involves js() helpers to bridge Kotlin and JavaScript execution contexts.
6Two-phase verification flow
Phone authentication occurs in distinct phases: verification initiation and code confirmation. The first phase uses verifyPhoneNumber() with a reCAPTCHA verifier, storing the returned verification ID. The second phase exchanges this ID and user-entered code for credentials via PhoneAuthProvider.credential(). The Kotlin/Wasm binding must maintain this stateful flow across Compose UI interactions. Error handling needs separate callbacks for verification failures versus code confirmation failures.
7Production vs development considerations
While test configurations simplify development, production deployments require careful validation. Developers must ensure testing flags like appVerificationDisabledForTesting are disabled. The production flow needs proper reCAPTCHA integration and real SMS delivery. Quota limits for SMS verifications apply in production but not during testing. The Kotlin/Wasm implementation should include environment checks to prevent accidental test configurations in released apps.
8Cross-platform implications
The Kotlin/Wasm phone auth implementation shares core concepts with Android and web approaches but requires Wasm-specific adaptations. The solution demonstrates how Firebase's JavaScript SDK can bridge to Kotlin environments beyond traditional web targets. This approach opens possibilities for sharing authentication logic across web, mobile, and desktop targets using Kotlin Multiplatform. The binding pattern could extend to other Firebase auth providers like email or OAuth flows.