microg/GmsCore · error · RuntimeException

No recaptcha token available

Error message

No recaptcha token available

What it means

FirebaseAuthService requires a reCAPTCHA token before sending an SMS verification code (phone auth). It resolves the token from, in order: the client-supplied request.recaptchaToken, the ReCaptchaOverlayService, or the legacy ReCaptchaActivity. If none is available it throws RuntimeException("No recaptcha token available"), meaning phone verification cannot proceed because Google's backend requires proof the request comes from a verified app.

Source

Thrown at firebase-auth/core/src/main/kotlin/org/microg/gms/firebase/auth/FirebaseAuthService.kt:376

                Log.w(TAG, "callback: onFailure", e)
                callbacks.onFailure(Status(CommonStatusCodes.INTERNAL_ERROR, e.message))
            }
        }
    }

    override fun sendEmailVerificationCompat(token: String?, actionCodeSettings: ActionCodeSettings?, callbacks: IFirebaseAuthCallbacks) {
        sendEmailVerification(SendEmailVerificationWithSettingsAidlRequest().apply { this.token = token; this.settings = actionCodeSettings }, callbacks)
    }

    override fun sendVerificationCode(request: SendVerificationCodeAidlRequest, callbacks: IFirebaseAuthCallbacks) {
        lifecycleScope.launchWhenStarted {
            try {
                Log.d(TAG, "sendVerificationCode")
                val reCaptchaToken = when {
                    request.request.recaptchaToken != null -> request.request.recaptchaToken
                    ReCaptchaOverlayService.isSupported(context) -> ReCaptchaOverlayService.awaitToken(context, apiKey, getAuthorizedDomain())
                    ReCaptchaActivity.isSupported(context) -> ReCaptchaActivity.awaitToken(context, apiKey, getAuthorizedDomain())
                    else -> throw RuntimeException("No recaptcha token available")
                }
                var sessionInfo: String? = null
                var registered = true
                val receiver = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {
                        var smsCode: String? = null
                        for (message in intent.getSmsMessages()) {
                            smsCode = Regex("\\b([0-9]{6})\\b").find(message.messageBody)?.groups?.get(1)?.value
                                    ?: continue
                            Log.d(TAG, "Received SMS verification code: $smsCode")
                            break
                        }
                        if (smsCode == null) return
                        registered = false
                        context.unregisterReceiver(this)
                        try {
                            callbacks.onVerificationCompletedResponse(PhoneAuthCredential().apply {
                                this.phoneNumber = request.request.phoneNumber

View on GitHub (pinned to 157c9d86ac)

Solutions

  1. Supply a valid recaptchaToken in the verification request obtained from the reCAPTCHA/Play Integrity verification flow for your app
  2. Call sendVerificationCode from a foreground Activity context so ReCaptchaActivity/overlay can present the challenge
  3. Verify microG is up to date and that ReCaptchaOverlayService/ReCaptchaActivity.isSupported(context) is true on the device
  4. Ensure the app's package name and signature are registered with the Firebase project so the authorized-domain check passes and token retrieval works

Example fix

// before: requesting code with no token, from background
val resp = auth.sendVerificationCodeCompat(request)
// after: fetch a token first and attach it
val token = ReCaptchaOverlayService.awaitToken(context, apiKey, authorizedDomain)
request.request.recaptchaToken = token
val resp = auth.sendVerificationCodeCompat(request)
Defensive patterns

Strategy: fallback

Validate before calling

fun canSendVerificationCode(context: Context): Boolean =
  ReCaptchaOverlayService.isSupported(context) || ReCaptchaActivity.isSupported(context)

Try / catch

try {
  auth.sendVerificationCodeCompat(request)
} catch (e: RuntimeException) {
  if (e.message == "No recaptcha token available") {
    // obtain a token via ReCaptchaOverlayService/ReCaptchaActivity, attach it, retry once
  } else throw e
}

Prevention

When it happens

Trigger: Calling sendVerificationCode (via sendVerificationCodeCompat) when: the request carries no recaptchaToken, the device/app cannot display the ReCaptcha overlay (unsupported context or missing overlay support), and ReCaptchaActivity-based flow is also unsupported (no suitable Activity to launch, e.g. caller lacks activity context or anti-abuse flow disabled).

Common situations: A client app calling the microG phone-auth endpoint without obtaining a reCAPTCHA token first; running on a device/ROM where the overlay service can't be bound; background caller (Service/WorkManager) with no foreground Activity, so the interactive reCAPTCHA challenge can't be shown; microG version where both reCAPTCHA paths report isSupported=false.

Related errors


AI-assisted analysis of microg/GmsCore@157c9d86ac (2026-09-06). Data as JSON: /api/errors/d2568c6899845cef. Report an issue: GitHub.