Anonymous User ID Authentication¶
This guide explains how to enable and integrate anonymous user id authentication with MimiCore inside MimiSDK.
Introduction¶
In Android MimiSDK 7.0.0, we introduced the ability to login an anonymous user using their anonymous user id.
The main use cases for this are partner integrations which want to support the possibility to associate an anonymous Mimi user with their own user account.
This would allow the anonymous Mimi user profile to: - Exist on multiple partner integrated products or, - To be restored on an app following a reinstall.
Building an integration¶
This section describes the individual steps involved for setting up a anonymous user id authentication flow with the MimiSDK.
This is an overview of the process:
Initializing MimiCore with allowAnonymousUserOnly=true
Warning
For data protection reasons it is essential that anonymous users do not become non-anonymous Mimi users, when using anonymous user id authentication.
Enabling the MimiConfiguration
option allowAnonymousUserOnly
will disable MimiSDK UI support for Mimi account login/signup.
When starting MimiCore
, you will need to pass in an instance of MimiConfiguration
with the flag allowAnonymousUserOnly
set to true
:
Login using anonymous id
If you already have an anonymous id to login from a previous session, then you should do so before opening the MimiSDK UI screens.
coroutineScope.launch {
val user = MimiCore.userController
.authenticate(MimiAuthRoute.LoginAnonymously(validAnonymousIdToLogin))
}
validAnonymousIdToLogin
is the anonymousId
which you have previously associated with your user and coroutineScope
is some Kotlin coroutine scope defined by you.
Note
Make sure the anonymous id is not a blank or empty string. It should be 36 characters in length.
Note
authenticate
is a network call and will propagate any exceptions raised by it.
Observing anonymous Id changes in the MimiSDK
The anonymous user is automatically created by the MimiSDK while the user onboards their Mimi profile.
This process happens asynchronously, so you need to observe changes in the MimiUser
and store the anonymousId value to associate it with your current app user.
coroutineScope.launch {
MimiCore.userController.mimiUser.observe {
val anonymousIdToStore = it.value?.anonymousId
TODO("Store this anonymousId to associate with your own user and login again in another session")
}
}
Note
observe
does not terminate, so you will need to control its execution through its coroutine Job
.
Note
anonymousId
will initially be null
on a clean start.
Samples¶
The following code sample may be useful to handle some of the details when performing the login step.
import io.mimi.sdk.core.MimiCore
import io.mimi.sdk.core.model.MimiAuthRoute
/*
* Sample code showing the key pieces of logic required when restoring a MimiUser via their
* anonymousId.
*/
class MimiAuthManager {
/**
* MimiAnonLoginResult
*
* Success - The given anonymousId has been successfully logged in, or was already logged in.
* Failure - There was a failure while logging in the anonymous user.
* Skipped - There was no action performed, as there's no valid user to login.
*
*/
sealed class MimiAnonLoginResult {
data class Success(val anonymousId: String) : MimiAnonLoginResult()
data class Failure(val exception: Exception) : MimiAnonLoginResult()
object Skipped : MimiAnonLoginResult()
}
/**
* Attempts to authenticate an anonymousId, if it is defined.
*
* @param anonymousIdToLogin the anonymousId currently associated with your user.
* @return See [MimiAnonLoginResult].
*/
internal suspend fun authenticateAnonymousUser(anonymousIdToLogin: String?): MimiAnonLoginResult {
// Important: Do not perform operation without allowAnonymousUserOnly!
if (!MimiCore.configuration.allowAnonymousUserOnly) {
return MimiAnonLoginResult
.Failure(IllegalArgumentException("Logging in an anonymous user is not supported unless MimiConfiguration allowAnonymousUserOnly=true"))
}
if (!anonymousIdToLogin.isAnonymousIdValidFormat()) {
// Nothing to restore, so return Skipped.
return MimiAnonLoginResult.Skipped
}
// Proceed with login
requireNotNull(anonymousIdToLogin) { "anonymousIdToLogin shouldn't be null here" }
return authenticateValidAnonymousUserId(anonymousIdToLogin)
}
private suspend fun authenticateValidAnonymousUserId(validAnonymousIdToLogin: String): MimiAnonLoginResult {
if (isAlreadyLoggedIn(validAnonymousIdToLogin)) {
// Already have the correct user logged in - don't need to do anything.
return MimiAnonLoginResult.Success(validAnonymousIdToLogin)
}
if (isDifferentUserLoggedIn(validAnonymousIdToLogin)) {
// Logout existing MSDK user
MimiCore.userController.logout()
}
// Login with the anonymous id
return try {
val user = MimiCore.userController
.authenticate(MimiAuthRoute.LoginAnonymously(validAnonymousIdToLogin))
MimiAnonLoginResult.Success(user.anonymousId)
} catch (e: Exception) {
MimiAnonLoginResult.Failure(e)
}
}
private fun isAlreadyLoggedIn(validAnonymousIdToLogin: String): Boolean {
return MimiCore.userController.mimiUser.state.value?.anonymousId == validAnonymousIdToLogin
}
private fun isDifferentUserLoggedIn(validAnonymousIdToLogin: String): Boolean {
val currentMsdkAnonymousId = MimiCore.userController.mimiUser.state.value?.anonymousId
return (!currentMsdkAnonymousId.isAnonymousIdValidFormat() && currentMsdkAnonymousId != validAnonymousIdToLogin)
}
// AnonymousId validity in terms of format only.
private fun String?.isAnonymousIdValidFormat(): Boolean {
return this?.let { length == ANONYMOUS_ID_LENGTH } ?: false
}
}
/**
* See [io.mimi.sdk.core.model.MimiUser]
*/
private const val ANONYMOUS_ID_LENGTH = 36