read 4 min
23 / 23
Dec 2022

Is no one else having this problem? I thought I could just rerun the sign in, but if I get a token that Mongo fails to recognise, I’m stuck with that token until Google decides to invalidate it. Calling GoogleSignInClient.signOut() does not invalidate the token.

My app is live, and intermittently broken for a good number of users, because of something seemingly out of my control. Any suggestions at all would be very gratefully received.

G’Day @Ada_Lovelace,

Thank you for raising your concern. I have reported this internally.

Please allow me some time to debug this and I will soon be back with any findings. Could you please confirm your forum registration email is also the email for your cloud project?

I appreciate your patience with us and I look forward to your response :slight_smile:

Warm Regards,

Hello @Ada_Lovelace,

I noticed multiple auth request errors of the form illegal base64 data at input byte 344 and crypto/rsa: verification error.

It is possible that somewhere in the code the token is getting invalid. I found a post on SO for Google SignIn validation. Please let me know if that is helpful in your case.

I look forward to hearing from you.

Cheers, :performing_arts:

Thanks for your reply. I took a look at the post you mentioned, but it doesn’t really help I’m afraid. I take the token from Google, and I pass it to MongoDb, there’s nothing really in between, so either Google is providing me with bad tokens, or Mongo is not accepting valid tokens.

Could I send you a token that is not working, so you can check this?

Hello @Ada_Lovelace ,

Thank you for your response. Sorry to hear the post was not helpful.

Could you share the full stack trace from the client application with me when this error is thrown? Please also share the valid and invalid tokens that allow and do not allow authentication to Cloud. I will share this with the engineering team internally to verify the reasons for not-accepting the tokens.

I look forward to your response.

Cheers, :performing_arts:

Sure thing, the stack trace is:

AUTH_ERROR(realm::app::ServiceError:47): illegal base64 data at input byte 349 at io.realm.internal.network.NetworkRequest.onError(NetworkRequest.java:68) at io.realm.internal.objectstore.OsJavaNetworkTransport.nativeHandleResponse(Native Method) at io.realm.internal.objectstore.OsJavaNetworkTransport.handleResponse(OsJavaNetworkTransport.java:98) at io.realm.internal.network.OkHttpNetworkTransport.lambda$sendRequestAsync$0$io-realm-internal-network-OkHttpNetworkTransport(OkHttpNetworkTransport.java:100) at io.realm.internal.network.OkHttpNetworkTransport$$ExternalSyntheticLambda0.run(Unknown Source:14) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:920)

Do you have an email address I can send the tokens to?

Hello Ada,

Thank you for sharing the requested information. Could you please also share the respective lines of code when this error is thrown?

Looking forward to your response.

Cheers, :performing_arts:

This is the code I’m using:

private fun initGoogleSignIn() { val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(RealmConsts.clientIdWeb.value) .build() mGoogleSignInClient = GoogleSignIn.getClient(this, gso) resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(result.data) onSignInResult(task) } } private fun onSignInResult(completedTask: Task<GoogleSignInAccount>) { try { Log.d("SIGN IN", "onSignInResult") val account = completedTask.getResult(ApiException::class.java) signInUser(account, // callback to UI here) } catch (e: ApiException) { // error handling removed for brevity } } fun signInUser (account: GoogleSignInAccount?, callback: ((Boolean) -> Unit)?) { viewModelScope.launch { val token = validateToken(account?.idToken) // this checks for non-unicode characters if (token == "") { // error handling return@launch } signInGoogle(token) // callback that handles the user here } fun signInGoogle (token: String, callback: (User?, String?) -> Unit) { signIn(Credentials.google(token, GoogleAuthType.ID_TOKEN), callback) } private fun signIn(credentials: Credentials, callback: (User?, String?) -> Unit){ try { app.loginAsync(credentials) { Log.d("HERE", "Async complete ${it.isSuccess}") if (it.isSuccess) { callback(it.get(), null) } else { // FAILS HERE } } } catch (e: Exception) { // error handling } } }

Thank you for sharing the requested information, Ada. I have raised this internally.

I will update you once I have more information to share.

Appreciate your patience with us on this.

Cheers, :performing_arts:

Hello @Ada_Lovelace ,

I wanted to update you that the engineering team is looking into this. There is a possibility that this may be an issue on Google’s side but I will be able to confirm once more information is available.

Appreciate your patience with us on this.

Regards,
Henna

With my login, it happens every single time now. I am unable to log in at all.

Thanks for the code example. I’ve made my own test in Kotlin, decoding just the secret from the token:

The secret decoded fine when using URL encoding using both java.util.Base64 and android.util.Base64 libraries, although when I put the same secret into the Go example, it gives an error.

try { val urlDecoded = java.util.Base64.getUrlDecoder().decode(secret) Log.d("JWT", "URL Decoded: $urlDecoded") } catch (e: Exception) { Log.d("JWT", "e: $e"); } // WORKS try { val decoded = java.util.Base64.getDecoder().decode(secret) Log.d("JWT", "Decoded: $decoded") } catch (e: Exception) { Log.d("JWT", "e: $e"); } // FAILS try { val androidDecoded = android.util.Base64.decode(secret, android.util.Base64.DEFAULT) Log.d("JWT", "Android Decoded DEFAULT: $androidDecoded") } catch (e: Exception) { Log.d("JWT", "e: $e"); } // FAILS try { val urlAndroidDecoded = android.util.Base64.decode(secret, android.util.Base64.URL_SAFE) Log.d("JWT", "Android Decoded URL_SAFE: $urlAndroidDecoded") } catch (e: Exception) { Log.d("JWT", "e: $e"); } // WORKS

OK, after a little testing (and learning Go!), I think I’ve found why the error is occuring - the token is presented without padding, meaning that base64.URLEncoding.DecodeString will not work (if the token length is not divisible exactly by the byte length), but base64.RawURLEncoding.DecodeString will.

I worked on this a little more, because currently I cannot use my app.

Adding padding to the token using:

private fun padToken (nonNullToken: String, padDivisor: Int = 4): String { val comps = nonNullToken.split(".") if (comps.size < 3) return "" var token = comps[2] val size = token.length val padAmount = ((ceil(size.toDouble() / padDivisor) * padDivisor) - size).toInt() token = token.padEnd(size + padAmount, '=') return "${comps[0]}.${comps[1]}.$token" }

generates a string that passes the Go playground above. However, it still does not allow me to sign in, and is also against the JWT spec (jwt.io reports that padded tokens are invalid)

5 months later

Hello @Rasvan_Andrei_Dumitr :wave:,

Thank you for raising your concern.

Could you confirm if your error is the same as @Ada_Lovelace “illegal base64 data at byte…” . Could you please share the error stack trace and code snippet giving the error?

I look forward to your response.

Cheers, :performing_arts:
Henna

1 month later

Hello @henna.s,

Yes i confirm. All my users are experiencing it.

private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) { showProgressDialog("Autentificare in curs!") try { if (completedTask.isSuccessful) { val account = completedTask.getResult(ApiException::class.java) val token = account.idToken val email: String? = account?.email val firstName = account?.givenName val googleCredentials = Credentials.google(token, GoogleAuthType.ID_TOKEN) taskApp?.loginAsync(googleCredentials) { it -> if (it.isSuccess) { Log.v( "AUTH", "Successfully logged in to MongoDB Realm using Google OAuth." ) Helpers().setLoginSuccesfoul(this, true) Helpers().setAuthProvider(this,"google") //TODO: 1 are limite setate in cont? daca nu are inseamna ca este un user now daca da inseamana ca este un user vechi checkifAccountIsNeeded(email, firstName) } else { hideProgressDialog() onLoginFailed("Nu s-a putut crea contul,${it.error}") Log.e( "AUTH", "Failed to log in to MongoDB Realm: ", it.error ) } } } else { Log.e( "AUTH", "Google Auth failed: " + completedTask.exception.toString() ) onLoginFailed("Google Auth failed:,${completedTask.exception.toString()}") } } catch (e: ApiException) { Log.w("AUTH", "Failed to log in with Google OAuth: " + e.message) onLoginFailed("Failed to log in with Google OAuth::,${e.message}") } }

Best regards,
Rasvan