androidsmooch

Smooch conversation recovery when server returning JWT's dies


I've integrated the Smooch/Sunshine Conversations SDK into our app.

On the most part, it works. However I've got a bit of an issue in a failure scenario:

  1. User is logged in (both to our service, and smooch)
  2. Our serverside dies for whatever reason, meaning JWT temporarily can't be fetched
  3. Conversation view shows "Cannot connect to server" (as expected)
  4. Our serverside recovers ... valid JWT's returned on request
  5. User tries to trigger a conversation in the app, and they continue to see "Cannot connect to server" indefinitely (even after moving back from the conversation activity and back into it).
  6. The Smooch SDK never recovers from this. The only way to solve it is to kill and restart the app.

I'm using the latest SDK version 7.0.3, and the vanilla ConversationActivity (I've not subclassed this or anything)

I've tried the following:

Any ideas?

Code:

        // This is in the Application class, as recommended
        fun initialiseSmooch(application: Application) {
            GlobalScope.launch {
                Log.i(TAG, "Initialising Smooch")

                val settings = Settings("INTEGRATION_ID")
                settings.authenticationDelegate = getAuthenticationDelegate()

                Smooch.init(application, settings, getInitialisationCallback())
            }
        }   

        private fun getInitialisationCallback(): (SmoochCallback.Response<InitializationStatus>) -> Unit {
            return { response ->
                if (response.data === InitializationStatus.SUCCESS) {
                    Log.i(TAG, "Smooch initialised successfully")
                } else {
                    Log.e(TAG, "Smooch initialization failed: ${response.error}")
                }
            }
        }

        /**
         * This basically tells the Smooch SDK what to do if the JWT is rejected. Basically it goes
         * and fetches a new token from our API.
         */
        private fun getAuthenticationDelegate(): AuthenticationDelegate {
            return AuthenticationDelegate(function = { authenticationError, authenticationCallback ->
                if (authenticationError != null && authenticationError.data != null) {
                    Log.w(TAG, authenticationError.data)
                }
                if(AppResources.repository.getUserId() == null){
                    Log.i(TAG, "Authentication error. User isn't logged in, so shouldn't be logged in to Smooch either.")
                    logoutSmoochUser()
                } else {
                    Log.i(TAG, "Authentication error. Getting new Smooch token.")
                    getSmoochToken { token -> authenticationCallback.updateToken(token) }
                }
            })
        }

        private fun getSmoochToken(callback: (String) -> Unit) {
          // Fetches token from API. If successful, callback is called
          // If unsuccessful, callback isn't called. This won't hang forever, it has a timeout.
        }


    // And to start the conversation
    private fun proceedToConversation() {
        ConversationActivity.builder().show(this)
    }


Solution

  • Please ensure you've implemented authentication delegates to automatically handle cases where JWTs are expired: https://docs.smooch.io/guide/authenticating-users/#expiring-jwts-on-sdks

    Once your backend issuing the JWTs comes back up, I'd start recovery attempts with a login() call.

    Finally, 10s JWT expiry is very short indeed.