Multi-account switching
Multi-account switching refers to a feature that stores account information at login or logout so that saved account information can be retrieved for quicker account switching during subsequent logins. It leverages previously authenticated account data to provide a faster and more convenient sign-in experience.
Flow and constraints¶
Before implementing multi-account switching, this section explains the operation flow and constraints.
The example flows below are sample scenarios intended as guidance for implementing multi-account switching. The exact ordering and storage methods may vary depending on the developer's environment.
Saving account information while signed in¶
This scenario shows how to save account information while the user is signed in after an explicit sign-in (explicit sign-in).
The result of this flow can be used for re-signing in with saved account information or deleting stored accounts later.
※ The method for storing and handling account data may differ depending on the game client implementation.
Saving account information when signing out¶
This scenario shows saving account information when a signed-in user logs out.
The result of this flow can be used for re-signing in with saved account information or deleting stored accounts later.
※ The method for storing and handling account data may differ depending on the game client implementation.
Re-signing in or deleting stored account information¶
This flow shows re-signing in using stored account information or deleting a specific account from the retrieved list — a practical scenario for implementing multi-account switching.
When a player selects an account from the PlayerID list UI implemented in the game, the behavior differs depending on whether the player is currently signed in.
※ The UI structure of the PlayerID list implemented by the game client may differ depending on the development environment.
Operational constraints¶
Consider the following constraints before implementing multi-account switching (see dev).
- Account information can only be stored while the user is signed in.
- Retrieving the saved account list (PlayerID list) or deleting saved account information is available regardless of sign-in state.
- Re-signing in using a saved account from the PlayerID list is only possible when in a signed-out state.
Implementation guide¶
This section describes how to implement multi-account switching using the SDK.
Follow the steps below and call the SDK APIs at each step to implement the features.
- After sign-in, store the currently signed-in account
- Retrieve the stored account information (PlayerID list) for sign-in or deletion
- Use the retrieved PlayerID list to show a PlayerID list UI when the user clicks "Account switch"
- Implement signing in with a stored account (PlayerID) or deleting a stored account (PlayerID) from the PlayerID list UI
1. Store the currently signed-in account¶
Store the account information for the currently signed-in user. Using stored account information enables faster sign-in later without repeating the full authentication flow.
In the game client, provide a UI element in account settings so that a signed-in user can store the current account at any time; when enabled, call the account storage API. Refer to the Saving account information while signed in scenario for flow examples.
You may also prompt the user during sign-out to ask if they want to save the current account; if the user chooses "Save and sign out", call the store API and then sign out. See the Saving account information when signing out scenario.
The example calls to store the current signed-in account are shown below.
2. Retrieve stored account information (PlayerID list)¶
Call the SDK to retrieve the stored account information (PlayerID list) saved in the SDK and authentication server. The game client can use the retrieved PlayerID list to populate a PlayerID list UI.
The example calls to retrieve the stored account list are shown below.
AuthV4.getStoredPlayerIdList(new AuthV4.AuthV4PlayerIdListListener() {
@Override
public void onAuthV4GetPlayerIdList(ResultAPI result, ArrayList<Long> playerIdList) {
if (result.isSuccess()) {
if(playerIdList != null) {
for(Long playerId : playerIdList) {
// API call succeeded
// playerId : player id
}
}
}
}
});
3. Sign in with a stored account (PlayerID)¶
Sign back in quickly using a stored account (PlayerID) while signed out — a core part of multi-account switching.
The typical flow is:
- After signing out, the user clicks "Account switch" on the sign-in screen → call the API to retrieve stored account information (PlayerID list)
- Show the PlayerID list UI using the retrieved list
Figure 3. Example: signing in using a saved account via "Account switch" -
When the user selects an account and signs in, call the API to sign in with the stored PlayerID. Example calls are shown below.
AuthV4.signInWithStoredPlayerId(playerId, useAutoSignIn, (ResultAPI result, AuthV4.PlayerInfo playerInfo)=>{ if (result.isSuccess()) { // Authentication succeeded // playerInfo : authenticated user info // Example: retrieve email foreach (KeyValuePair<AuthV4.ProviderType, AuthV4.ProviderInfo> entry in playerInfo.providerInfoData) { AuthV4.ProviderInfo providerInfo = entry.Value; if(providerInfo.providerEmail != null && providerInfo.providerEmail != "") { string email = providerInfo.providerEmail; break; } } } else if (result.needExit()) { // TODO: implement app exit // e.g. Application.Quit(); } });
FHiveAuthV4::SignInWithStoredPlayerId(playerId, useAutoSignIn, FHiveAuthV4OnSignInDelegate::CreateLambda([this](const FHiveResultAPI& Result, const FHivePlayerInfo& PlayerInfo) { if (Result.IsSuccess()) { // Authentication succeeded (PlayerInfo: authenticated user info) // Example: retrieve email for (const auto& ProviderInfoEntry : PlayerInfo.ProviderInfoData) { FHiveProviderInfo ProviderInfo = ProviderInfoEntry.Value; FString Email = ProviderInfo.ProviderEmail; } } else if (Result.NeedExit()) { // TODO: implement app exit // e.g. UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false); } }));
AuthV4::signInWithStoredPlayerId(playerId, useAutoSignIn, [=](ResultAPI const & result, PlayerInfo const & playerInfo) { if (result.isSuccess()) { // Authentication succeeded // playerInfo: authenticated user info // Example: retrieve email for(auto it = playerInfo.providerInfoData.begin(); it != playerInfo.providerInfoData.end(); ++it) { hive::ProviderInfo providerInfo = it->second; if(!providerInfo.providerEmail.empty()) { std::string email = providerInfo.providerEmail; break; } } } else if (result.needExit()) { // TODO: implement app exit // Cocos2d-x users: e.g. exit(0); // Unreal users: e.g. UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, false); } });
```java AuthV4.signInWithStoredPlayerId(playerId, useAutoSignInState, object : AuthV4.AuthV4SignInListener { override fun onAuthV4SignIn(result: ResultAPI, playerInfo: AuthV4.PlayerInfo?) { if (result.isSuccess) { // Authentication succeeded // playerInfo: authenticated user info
// Example: retrieve email playerInfo?.let { for ((key, value) in it.providerInfoData) { var providerInfo: AuthV4.ProviderInfo = value if(providerInfo.providerEmail.isNotEmpty()) { val email = providerInfo.providerEmail break } } } } else if (result.needExit()) { // TODO: implement app exit // e.g. exitProcess(0) } } }) ```
AuthV4.signInWithStoredPlayerId(playerId, useAutoSignInState, new AuthV4.AuthV4SignInListener() { @Override public void onAuthV4SignIn(ResultAPI result, AuthV4.PlayerInfo playerInfo) { if (result.isSuccess()) { // Authentication succeeded // playerInfo: authenticated user info // Example: retrieve email if(playerInfo != null) { for (Map.Entry<AuthV4.ProviderType, AuthV4.ProviderInfo> entry : playerInfo.getProviderInfoData().entrySet()) { AuthV4.ProviderInfo providerInfo = entry.getValue(); if (providerInfo.getProviderEmail() != "") { String email = providerInfo.getProviderEmail(); break; } } } } else if (result.needExit()) { // TODO: implement app exit // e.g. System.exit(0); } } });
AuthV4Interface.signInWithStoredPlayerId(playerId, useAutoSignIn: useAutoSignInState) { (result, playerInfo) in if result.isSuccess() { // Authentication succeeded // playerInfo: authenticated user info // Example: retrieve email if let playerInfo = playerInfo { // Find providerInfo with non-empty providerEmail (the provider used for current login) for key in playerInfo.providerInfoData.keys { if let providerInfo = playerInfo.providerInfoData[key], providerInfo.providerEmail.count > 0 { // providerEmail != "" email = providerInfo.providerEmail break } } } } else if result.needExit() { // TODO: implement app exit // e.g. exit(0) } }
[HIVEAuthV4 signInWithStoredPlayerId: playerId useAutoSignIn: useAutoSignIn handler:^(HIVEResultAPI *result, HIVEPlayerInfo *playerInfo) { if([result isSuccess]){ // Authentication succeeded // playerInfo: authenticated user info // Example: retrieve email if(playerInfo != nil) { // Find providerInfo entry with non-empty providerEmail (the provider used for current login) for (NSString* key in playerInfo.providerInfoData.allKeys) { HIVEProviderInfo* providerInfo = playerInfo.providerInfoData[key]; if (providerInfo != nil && providerInfo.providerEmail.length > 0) { // providerEmail != "" email = providerInfo.providerEmail; break; } } } } else if ([result needExit]) { // TODO: implement app exit // e.g. exit(0); } }];
4. Delete a stored account (PlayerID)¶
Delete a stored account (PlayerID) using the multi-account switching UI while signed out.
From the exposed PlayerID list UI, the user may choose to delete a stored account instead of signing in.
Call the API to delete the stored account as shown below.
Error codes¶
Descriptions of error codes returned by the SDK while implementing multi-account switching.
Error Code | Message | Description |
NEED_INITIALIZE | AuthV4NotInitialized | When the SDK is not initialized (AuthV4.setup) |
IN_PROGRESS | AuthV4InProgress | When the API is called again before receiving a response |
INVALID_SESSION | AuthV4SessionNotExist | When the requested PlayerID does not exist in the list |
INVALID_SESSION | AuthV4SessionProcessingFail | Session save/delete failed |
Implementation notes¶
Keep the following points in mind when implementing multi-account switching.
-
API consecutive call limits
If you repeatedly call the API before receiving a response, you may not receive a valid response. Always wait for the API response before making the next call.
-
Be careful with how login sessions are stored
Login sessions are stored on a device basis, not by signed-in account. Depending on the implementation, saved login information may be exposed to other users of the same device. For security-sensitive services, consider whether storing login sessions is appropriate.
-
Do not use multi-account switching when COPPA applies (ageGateU13 = true)
Multi-account switching stores account information and enables faster sign-in, but when COPPA applies, do not store account information or provide session-based sign-in for affected users.
The SDK does not automatically restrict the use of the multi-account login management feature, so additional handling in the game is required. Additionally, COPPA restricts the collection, use, and sharing of personal information for users under 13 years of age, so it is recommended to avoid storing related data, including session information.
-
AuthV4.signOut
If the account targeted by the
AuthV4.signOut
call exists in the PlayerID list, the login session must be maintained, so a session expiration request is not sent to the server. Therefore,AuthV4.signOut
returns success regardless of the current network connection state.