Skip to content

Firebase Auth - only errors returned from signInWithEmailAndPassword as success hangs #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
meavydev opened this issue Feb 24, 2025 · 2 comments

Comments

@meavydev
Copy link

This is running on a Kobweb API call under JVM, so there could be some different initialisation in there.

Stepping through the code, it appears that the enqueueRefreshTokenCall is hanging on this line:

It goes through the successful response and then sets up the refresh token call...

            override fun onResponse(call: Call, response: Response) {
                if (!response.isSuccessful) {
                    source.setException(
                        createAuthInvalidUserException("verifyPassword", request, response)
                    )
                } else {
                    val body = response.body()!!.use { it.string() }
                    val user = FirebaseUserImpl(app, jsonParser.parseToJsonElement(body).jsonObject)
                    refreshToken(user, source) { AuthResult { it } }
                }
            }

Which calls the enqueueRefreshTokenCall...

    internal fun <T> refreshToken(user: FirebaseUserImpl, source: TaskCompletionSource<T>, map: (user: FirebaseUserImpl) -> T?) {
        refreshSource = refreshSource
            .takeUnless { it.task.isComplete }
            ?: enqueueRefreshTokenCall(user)
        refreshSource.task.addOnSuccessListener { source.setResult(map(it)) }
        refreshSource.task.addOnFailureListener { source.setException(it) }
    }

Which gets back a successful response with the token, but the [email protected] = user line never completes, so the source.setResult call never occurs. Hence the hang.


            @Throws(IOException::class)
            override fun onResponse(call: Call, response: Response) {
                val body = response.body()?.use { it.string() }
                if (!response.isSuccessful) {
                    signOutAndThrowInvalidUserException(body.orEmpty(), "token API returned an error: $body")
                } else {
                    jsonParser.parseToJsonElement(body!!).jsonObject.apply {
                        val user = FirebaseUserImpl(app, this, user.isAnonymous)
                        if (user.claims["aud"] != app.options.projectId) {
                            signOutAndThrowInvalidUserException(
                                user.claims.toString(),
                                "Project ID's do not match ${user.claims["aud"]} != ${app.options.projectId}"
                            )
                        } else {
                            [email protected] = user
                            source.setResult(user)
                        }
                    }
                }
            }

My Kobweb code is actually using firebase-kotlin-sdk 2.1.0 and the latest Kobweb with Kotlin 2.

@meavydev
Copy link
Author

meavydev commented Feb 24, 2025

Actually I just realised there is code behind the FirebaseAuth.user assignment and the problem is that it uses:

                GlobalScope.launch(Dispatchers.Main) {

Which is obviously a bad thing to do, as GlobalScope is one of the things that they say never to use... plus the documentation on Dispatchers.Main for JVM says Android / Swing / JavaFX, so I'm guessing there is no implementation that would work on the Kobweb API backend JVM.

On Kobweb this just hangs and none of the code in this section runs:

                GlobalScope.launch(Dispatchers.Main) {
                    if (prev?.uid != value?.uid) {
                        authStateListeners.forEach { l -> l.onAuthStateChanged(this@FirebaseAuth) }
                    }

                    if (prev?.idToken != value?.idToken) {
                        val result = InternalTokenResult(value?.idToken)
                        for (listener in internalIdTokenListeners) {
                            Log.i("FirebaseAuth", "Calling onIdTokenChanged for ${value?.uid} on listener $listener")
                            listener.onIdTokenChanged(result)
                        }
                        for (listener in idTokenListeners) {
                            listener.onIdTokenChanged(this@FirebaseAuth)
                        }
                    }
                }

@meavydev
Copy link
Author

Actually as a quick hack I have taken a local copy of firebase-java-sdk and removed all the Dispatchers.Main in FirebaseAuth.kt and this has got me further.
So I really think you need to reasses the use of GlobalScope.launch(Dispatchers.Main) and replace them with something that is more cross platform friendly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant