Appearance
Appearance
When using social logins, it is possible that different login providers have conflicting results. For example, a player could have their Facebook account associated with a certain game account and their current device associated with some other account. This could happen if they have played the game earlier while logged into Facebook and then uninstalled the game or have played the game on a different device. In these situations, we need to be able to resolve the situation somehow to be able to use and update the correct Game Account. While conflict resolution can be a lot of work, the good news is it's platform agnostic, so you only have to do it once!
Let's use the above example, where the user has either played the game while logged into Facebook and then uninstalled it or played the game on a different device. If they later reinstall the game or decide to register with Facebook on the current device, we have a conflict: their current account is different from the one indicated by Facebook.
Initial state:
+- Device A ---------------------+
| [ Device ] --> [ Account A ] |
+--------------------------------+
+- Device B----------------------+
| [ Device ] --> [ Account B ] |
| [ Facebook ] --> [ Account B ] |
+--------------------------------+
Player on device A logs in with Facebook:
+- Device A ---------------------+
| [ Device ] --> [ Account A ] |
| [ Facebook ] --> [ Account B ] |
+--------------------------------+
+- Device B ---------------------+
| [ Device ] --> [ Account B ] |
| [ Facebook ] --> [ Account B ] |
+--------------------------------+
Now we have conflicting login information. A Social Platform disagrees with the bound device account. The client on device A must now choose:
The player throws away their current state and switches to the account they used previously with the Facebook account. Account A becomes inaccessible (unless there is some other Social Platform bound to that account that was not shown here).
This option is chosen by sending SocialAuthenticateResolveConflict(platform, useOther: true)
. Since the current device account changes, the session will restart.
The resulting state is as follows:
+- Device A ---------------------+
| [ Device ] --> [ Account B ] |
| [ Facebook ] --> [ Account B ] |
+--------------------------------+
+- Device B ---------------------+
| [ Device ] --> [ Account B ] |
| [ Facebook ] --> [ Account B ] |
+--------------------------------+
Following event log entries are recorded:
For Account A (Player A in Dashboard):
+-----------------------------------------------------------------------------------+
| Social Authentication Conflict Resolved: |
| Device removed. |
| Device DeviceId/<DEVICEID_A> migrated from this player onto Player:<PLAYER_B_ID>. |
| Synchronized with <SOCIAL_AUTH_ID> social login. |
+-----------------------------------------------------------------------------------+
For Account B (Player B in Dashboard):
+-----------------------------------------------------------------------------------+
| Social Authentication Conflict Resolved: |
| Device added. |
| Device DeviceId/<DEVICEID_A> migrated to this player from Player:<PLAYER_A_ID>. |
| Synchronized with <SOCIAL_AUTH_ID> social login. |
+-----------------------------------------------------------------------------------+
The player binds the Facebook account to their current Game Account. This option is chosen by sending SocialAuthenticateResolveConflict(platform, useOther: false)
.
The resulting state is as follows:
+- Device A ---------------------+
| [ Device ] --> [ Account A ] |
| [ Facebook ] --> [ Account A ] |
+--------------------------------+
+- Device B ---------------------+
| [ Device ] --> [ Account B ] |
| [ Facebook ] --> [ Account A ] |
+--------------------------------+
Following event log entries are recorded:
For Account A (Player A in Dashboard):
+------------------------------------------------------------------------------------+
| Social Authentication Conflict Resolved: |
| Social login added. |
| Login account <SOCIAL_AUTH_ID> migrated to this player from Player:<PLAYER_B_ID>. |
+------------------------------------------------------------------------------------+
For Account B (Player B in Dashboard):
+------------------------------------------------------------------------------------+
| Social Authentication Conflict Resolved: |
| Social login removed. |
| Login account <SOCIAL_AUTH_ID> migrated from this player onto Player:<PLAYER_A_ID> |
+------------------------------------------------------------------------------------+
As seen above, this puts device B in a conflicting state. In some cases, this is completely harmless: If device B is an uninstalled app, an app on a recycled old phone, or otherwise unused account, this is not a problem as the account is no longer logged into.
In the case, however, the user logs in with device B, it will require another conflict resolution. Now the client may choose to rebind the Facebook account to this account to cancel the previous operation or switch this device too to the (presumably primary) account A.
If neither of the options above is acceptable, it is possible to resolve the conflict without any migrations. Unresolved conflicts will be cleared automatically when the session ends. The client should also log out from the Social Platform (in this case, Facebook) to prevent the same conflict on the next app startup.
No event log entries are recorded.
As we saw above, the desired resolution depends on the user's intent. Hence, the application must ask for user intent in the case of a conflict to handle all possible cases. Here, this process is called a Complete Flow. However, as developing the necessary UIs for the Complete Flow is a non-trivial amount of work, we also present a Minimal Flow that solves the trivially solvable conflicts with no UI work.
ConflictingPlayer
.PlayerModel
) is very low level and has very little or no progress, resolve conflict with useOther = true
.ConflictingPlayer
) is very low level and has very little or no progress, resolve conflict with useOther = false
.ConflictingPlayer
and prompt the player to choose one of the strategies above: useOther = true
)useOther = false
)ConflictingPlayer
.PlayerModel
) is very low level and has very little or no progress, resolve conflict with useOther = true
.ConflictingPlayer
) is very low level and has very little or no progress, resolve conflict with useOther = false
.Steps 2 and 3 provide automatic resolution in cases where the chosen resolution is very likely the correct one, and choosing wrong has very limited damage. This not only smoothens the user experience when the player starts the game on a new device, but it also protects the player from choosing wrong and accidentally losing access to their existing game state.
💡 Hint
PlayerModel.Stats.CreatedAt
can be used to determine if either account was created very recently and hence is unlikely to have any meaningful progress.
As players may not understand the consequences of step 4 in Complete Flow, there is a non-zero risk that users unintentionally select a wrong option. To resolve the situation, customer service may manually fix the attached authentication methods for the player. The wrong options can be reverted as follows:
Social Authentication Conflict Resolved
event which matches the description of the player. For example, if the player describes logging in with Facebook, the matching entry should have a Facebook/<somelongtoken>
Social Login ID in its description.... migrated to this player from Player:ABC.
, the lost account is Player:ABC
.Player:ABC
and select Reconnect Devices. Input the player's current ID and check the preview. If the preview looks sensible, i.e., the desired authentication method is listed in Devices & Social Auths on the left, accept the reconnect.Metaplay supports various Social Platforms. After going through this guide and the previous Getting Started with Social Logins, you should have everything you need to have a fully functioning implementation.
Here are the guides for specific Social Platforms that are currently available: