Skip to content

Implement automatic login

To implement automatic login with the recipe code, complete the following procedure in order.

Before you begin, complete the common prerequisites.

Overall flow

What you configure and call in each step is as follows.

Step Category What you do
1 Hive Console Check the Client ID
2 Hive Axyl SDK Install the authentication module and the secure storage module
3 Hive Axyl SDK Initialize the SDK and register modules
4 Recipe code Copy the recipe folder
5 App code Prepare the credential store
6 Hive Axyl SDK, App code Save credentials right after login
7 Recipe code Call automatic login at app launch
8 App code Handle restoration results
9 Hive Axyl SDK, App code Enable automatic access token refresh
10 App server, Hive Axyl Server API Validate access tokens on the app server
11 App code Verify the behavior
Saved credentials must match the latest tokens in the session

The Hive Axyl authentication server replaces the refresh token with a new value each time it is used and invalidates the previous value. If the saved refresh token is an outdated value, automatic login is rejected on the next launch once the access token has also expired. Each time new tokens are issued for the session, replace the saved values in the same way as in step 6. Step 9 describes how to detect when a refresh happens.

1. Check the Client ID in the Hive Console

  • Hive Console  Configure or check this in the Hive Console.

In the Hive Console, check the Client ID to use for session restoration. You enter this value when you create the recipe in step 7.

Setting Required Where to check
Check the Client ID Required Get the security key
Do not put the Client Secret in the app client

The recipe uses only the Client ID. If the Client Secret leaks from the app client, malicious users can call the API without authorization.

2. Install SDK modules

  • Hive Axyl SDK  Call the Hive Axyl SDK from the app.


    Detailed procedure: Install modules

Install the authentication module and the secure storage module in your Unity project. The secure storage module is used to encrypt and keep the access token and refresh token on the device.

Package Needed Role
com.com2usplatform.hiveaxyl.core Required SDK initialization and login session management
com.com2usplatform.hiveaxyl.auth Required Login with saved tokens and token issuance
com.com2usplatform.hiveaxyl.storage Recommended Encrypted storage of the access token and refresh token

If your app already uses secure storage, you do not need to install com.com2usplatform.hiveaxyl.storage. However, even in this case, the app must be able to read the access token, refresh token, and Player ID after it restarts.

3. Initialize the SDK

Initialize the SDK once at the app's entry point, and register the authentication, token, and secure storage modules. The recipe does not initialize the SDK, so calling it without initialization fails with a FailedPrecondition error.

The following example code registers the modules needed for automatic login and initializes the SDK.

using Hive.Axyl.Auth;
using Hive.Axyl.Core;
using Hive.Axyl.Core.Unity;
using Hive.Axyl.Storage;

var config = CoreConfig.CreateBuilder("{appId}").Build();

HiveBootstrap.Initialize(config, builder =>
{
    builder
        .AddAuth()
        .AddToken()
        .AddSecureStorage();
});

For {appId}, enter the App ID you created in the Hive Console.

If you do not register AddAuth() and AddToken(), the recipe fails with a FailedPrecondition error. If your app uses another secure storage, you do not need to register AddSecureStorage().

4. Install the recipe code

  • Recipe code  Copy the recipe code into your project.

A recipe is source code that you copy into your project instead of installing as a package. Copy the following items from the axyl-samples-unity repository to Assets/Recipes/ in your Unity project.

The items to copy and their roles are as follows.

  • Recipes.asmdef: Common assembly definition for recipes
  • AssemblyInfo.cs: Setting that exposes internal helpers to other recipe assemblies
  • Helper/: Common code shared by multiple recipes
  • AutoLogin/: AutoLoginRecipe, StoredSession, and result types

To call recipes from your app code, add the following assembly to references in your app's assembly definition. Because autoReferenced in the original Recipes.asmdef is false, your app assemblies do not reference it automatically.

{
  "name": "MyApp",
  "references": [
    "Hive.Axyl.Core",
    "Hive.Axyl.Auth",
    "Hive.Axyl.Storage",
    "Hive.Axyl.Samples.Recipes"
  ]
}

Replace MyApp with the assembly name your app uses, and keep your existing settings and references. Unity assemblies do not pass references on transitively, so you must list here every assembly that your app code uses directly. Hive.Axyl.Core contains CoreConfig and HiveError, Hive.Axyl.Auth contains AddAuth() and AddToken(), and Hive.Axyl.Storage contains AddSecureStorage(). If you do not register AddSecureStorage(), you do not need to list Hive.Axyl.Storage.

The code does not compile if you copy only AutoLogin/

AutoLoginRecipe uses the common code in Helper/. PKCE value generation, reading token expiration times, SDK result classification, and session preparation are all there. Copy Helper/, Recipes.asmdef, and AssemblyInfo.cs together.

5. Prepare the credential store

The credentials you pass to the recipe are in the StoredSession format and consist of the access token, refresh token, and Player ID. The recipe does not save or delete these values, so the app creates the store itself.

The meaning of the three values is as follows.

  • AccessToken: The access token that the previous run used last. It can be an expired value
  • RefreshToken: The refresh token that the previous run used last
  • PlayerId: The Player ID of the user that the two tokens refer to

The Hive Axyl SDK keeps the session only in memory, so all three values disappear when the app quits. A token is a credential that can act on behalf of the user until it expires, so keep it in encrypted storage, such as the device secure storage that com.com2usplatform.hiveaxyl.storage provides.

The DeviceKey and guest credentials used for login are not included in StoredSession. These two values are used by the login features, so keep them separately as described in the login practical guides.

Create a store component in your app that provides the following three operations. The example code below calls this store storedSessionStore.

Operation Method in the example code Return value Description
Load LoadAsync() StoredSession or null Reads the three stored values and re-creates them with StoredSession.Create(). Returns null if there is no value.
Save SaveAsync() None Replaces the existing values with the three values of the StoredSession it receives.
Delete DeleteAsync() None Deletes the stored values.

All three operations wait for storage access, so make them asynchronous methods that also take the CancellationToken of the calling screen.

Re-create StoredSession from the three saved values

JsonUtility does not save the property values of StoredSession. Move the two tokens and PlayerId into a separate type that has them as public fields and save that type, and when you load them, call StoredSession.Create() with those values.

StoredSession.Create() throws an ArgumentException if both tokens are empty or if PlayerId is 0 or less. If there are no stored values, do not create an empty StoredSession; return null and pass it to the recipe as is.

When the store does not work normally, handle each situation separately. If you use com.com2usplatform.hiveaxyl.storage, distinguish the situations by the results of the save and read calls.

Situation Result value Handling
Storage access denied AccessDenied Show the login screen without deleting the stored values
Temporary failure or unknown result Failure (Problem.Code is Internal or similar), UnknownOutcome Show the login screen without deleting the stored values
Confirmed corruption of the stored data DataCorrupted Reset the storage, and then show the login screen

Handle storage access denial and data corruption differently. If access is denied or a temporary failure occurs, the existing data may still remain, so you must not reset the storage.

6. Save credentials right after login

  • Hive Axyl SDK  Call the Hive Axyl SDK from the app.

    App code  Implement this in the app.


    Detailed procedure: Save credentials

Right after the user logs in and the session is activated, read the session's tokens and save them. If you skip this step, there is nothing to restore on the next launch.

ISessionManager.GetSnapshot() returns the current session's access token, refresh token, and Player ID at once. Create a StoredSession with these values and pass it to the store from step 5. When there is no session, the three values are empty and StoredSession.Create() throws an ArgumentException, so check the session with IsLoggedIn first.

using Hive.Axyl.Core;
using Hive.Axyl.Samples.Recipes;

StoredSession CaptureStoredSession()
{
    ISessionManager session = HiveCore.Resolve<ISessionManager>();
    if (!session.IsLoggedIn)
    {
        return null;
    }

    SessionSnapshot snapshot = session.GetSnapshot();

    return StoredSession.Create(
        snapshot.AccessToken, snapshot.RefreshToken, snapshot.PlayerId);
}

StoredSession captured = CaptureStoredSession();
if (captured != null)
{
    await storedSessionStore.SaveAsync(captured, cancellationToken);
}

cancellationToken is the CancellationToken of the login screen that calls the save.

CaptureStoredSession() is also used in step 8. When automatic login succeeds, a new pair of tokens is issued, so you must replace the saved values at that point as well.

7. Call automatic login

  • Recipe code  Call the recipe code from the app.

When the app launches, load the saved credentials and pass them to LoginAsync(). If the value is null, the recipe returns NoSession without attempting restoration, so the app does not need to check in advance whether saved values exist.

Call it only when there is no session

When restoration succeeds, the recipe installs the session. If you call it while already logged in, the session that was just created is replaced. Call it only once, after the app launches and before you draw the login screen.

Also prepare a CancellationTokenSource so that you can stop waiting if the user leaves the start screen.

using System.Threading;
using Hive.Axyl.Samples.Recipes;

var recipe = new AutoLoginRecipe(clientId);

var cancellation = new CancellationTokenSource();
CancellationToken cancellationToken = cancellation.Token;

StoredSession stored = await storedSessionStore.LoadAsync(cancellationToken);

AutoLoginOutcome outcome = await recipe.LoginAsync(stored, cancellationToken);

For clientId, enter the value you checked in step 1. If you pass an empty value, the constructor throws an ArgumentException. Call cancellation.Cancel() when the user leaves the start screen or selects cancel, and clean up with cancellation.Dispose() when the call ends.

The recipe reads the expiration time of the saved access token and selects one of the two restoration paths, only once. If one path fails, it does not move on to the other path, and if no usable token exists, it does not start restoration.

  • More than 30 seconds remain until the access token expires: Logs in with the access token, and then issues a new pair of tokens
  • A refresh token exists, but the access token is missing, has expired, or has an expiration time that cannot be read: Exchanges the refresh token for a new pair of tokens
  • No usable token exists at all: Returns NoSession with StoredCredentialIsStale set to true, without attempting restoration

The recipe performs the following tasks internally.

Category Call Where to check
Recipe code Creates a pair of PKCE values and passes them separately to the login call and the token issuance call Restore with the saved access token
Hive Axyl SDK Validates the saved access token and issues an authorization code with LoginWithAccessTokenAsync() Restore with the saved access token
Hive Axyl SDK Exchanges the authorization code for an access token and a refresh token with IssueTokenAsync() Issue an access token and a refresh token
Hive Axyl SDK Exchanges the saved refresh token for a new pair of tokens with IssueTokenAsync() Restore with the saved refresh token
Hive Axyl SDK Activates the login session with SetSession() Activate the session

The session is activated only once, after restoration is fully complete. If restoration fails midway, no session is created, so you do not need to clean up the session yourself after a failure.

On the access token path, the recipe compares the Player ID returned by the server with the saved Player ID. If the two values differ, a session for a different account could be created, so the recipe stops before the token exchange and returns Failure as Status and HiveErrorCode.FailedPrecondition as Error.Code. In this case, the saved values remain as they are, so guide the user to log in manually.

The detailed procedures in the table above are written for calling the Hive Axyl SDK methods directly. Do not reimplement in the app the steps that the recipe handles for you, such as creating PKCE values. Refer to them only to check what each call sends and receives.

8. Handle restoration results

AutoLoginOutcome reports the restoration result through Status, and whether to keep the saved values through StoredCredentialIsStale. The two values are independent of each other, so check both.

Status Value to check App handling
Success PlayerId, IsBlocked The session is activated. Replace the saved values with the new tokens, and if the user is not under a usage restriction, move to the app screen.
NoSession StoredCredentialIsStale There are no values to restore. false means either the first launch with no saved values at all or a logged-out state, and true means that saved values exist but no usable token remains. In both cases, show the login screen, and when it is true, also delete the saved values.
BusinessOutcome BusinessOutcome, UnknownOutcomeCode, RawJson Branch according to the rejection reason, and handle unknown values as failures and record them.
Failure Error.Code, Error.TraceId Record the technical problem, and show the login screen while keeping the saved values.
if (outcome.Status == AutoLoginStatus.Success)
{
    // A new pair of tokens was issued during restoration. Replace the saved values.
    await storedSessionStore.SaveAsync(CaptureStoredSession(), cancellationToken);

    if (outcome.IsBlocked == true)
    {
        // The user is under a usage restriction. Do not move to the app screen.
        ShowRestrictionNotice();
    }
    else
    {
        // null means that this restoration did not check the usage restriction status.
        EnterApp(outcome.PlayerId);
    }
}
else if (outcome.StoredCredentialIsStale)
{
    // The session can no longer be restored with the saved values.
    await storedSessionStore.DeleteAsync(cancellationToken);
    ShowLoginScreen();
}
else
{
    // Keep the saved values and show the login screen.
    ShowLoginScreen();
}

EnterApp(), ShowRestrictionNotice(), and ShowLoginScreen() are the app's screen transition code.

StoredCredentialIsStale being false does not guarantee that the saved values can be used again. On the refresh token path, the token may already have been consumed before the response was received. Do not delete the values, but do not call again right away either. For the cases in which it is safe to call again with the same values, see Failure handling.

IsBlocked is a bool? type that has three values: true, false, and null. It is filled with the usage restriction status returned by the server only when restoration succeeds through the access token path. When restoration uses the refresh token path, and for every result other than success, it is null. This is because the refresh token path only exchanges tokens and does not check the user's status.

If it is true, the user is under a usage restriction, so block entry to the app. null does not mean that there is no usage restriction; it means that this restoration did not check it. If you need to check the usage restriction status regardless of the restoration path, call Usage restriction separately.

FailedStep is a diagnostic value that tells you at which step the process stopped. Use it only for error logging, and do not use it as the basis for branching the app's screen flow.

If you cancel restoration with the CancellationToken, Status becomes Failure and Error.Code becomes HiveErrorCode.Cancelled. In this case, no session is created.

9. Enable automatic access token refresh

The access token of a restored session also expires over time, so if you turn on automatic refresh, users do not need to log in again during play. With automatic refresh on, when a method is called with an expired token, the Hive Axyl SDK gets new tokens with the refresh token, refreshes the session, and continues processing the original request.

using System.Threading;
using Hive.Axyl.Auth;
using Hive.Axyl.Core;
using Hive.Axyl.Samples.Recipes;

// Call this only once after SDK initialization. baseUrl is the same value as the token server host that ITokenService uses.
AuthTokenRefresh.Enable("{baseUrl}", "{clientId}");

// The following are members of the component that subscribes to session events.
private ISessionManager m_session;

private void Start()
{
    m_session = HiveCore.Resolve<ISessionManager>();
    m_session.OnSessionRefreshed += SaveRefreshedSession;
}

private void OnDestroy()
{
    m_session.OnSessionRefreshed -= SaveRefreshedSession;
}

// Apply the refreshed tokens to the store.
private async void SaveRefreshedSession(SessionSnapshot snapshot)
{
    var refreshed = StoredSession.Create(
        snapshot.AccessToken, snapshot.RefreshToken, snapshot.PlayerId);

    await storedSessionStore.SaveAsync(refreshed, CancellationToken.None);
}

For {baseUrl}, enter the address of the token server that ITokenService connects to. If you registered AddToken() without arguments as in step 3, it is https://core-api.hiveaxyl.com. For {clientId}, enter the value you checked in step 1. You can call Enable() only once. Calling it before initializing the SDK or calling it twice throws an InvalidOperationException. When the subscribing component is destroyed, unsubscribe from both OnSessionRefreshed and the OnSessionExpired event you subscribe to in 9.2, as OnDestroy() does in the example code.

9.1. Save refreshed tokens

Tokens issued by automatic refresh are applied only to the session, not to the store. ISessionManager.OnSessionRefreshed is raised with the latest SessionSnapshot each time new tokens are registered for the session, so subscribe to this event and replace the saved values. If you leave out this subscription, the saved refresh token becomes outdated, and automatic login on the next launch is rejected.

Before you log out or log in with another account and change the saved values, wait for any in-progress save to finish. If a save finishes later than the deletion, the deleted information comes back, and on the next launch the app logs in again with the account that logged out.

9.2. Handle session termination

When the refresh token has also expired, automatic refresh fails and the session ends. Subscribe to the ISessionManager.OnSessionExpired event to detect this situation, delete the saved values of the ended session, and then direct the user to the login screen. This event is also raised when you clean up the session yourself, such as when logging out.

This event does not tell you which account's session ended. Have the app remember which account the current session belongs to, and delete only that account's saved values. Do not delete the saved values of other accounts or the guest credentials.

Do not delete the saved values if the session ends without the event

If token refresh fails three times in a row without confirming validity, the session ends without OnSessionExpired, and IsLoggedIn becomes false. In this case, the saved values are still valid, so do not delete them; create the session again with the automatic login in step 7. For the conditions under which this occurs, see OnSessionExpired.

10. Validate access tokens on the app server

If your app's app server handles play data, you must validate requests sent from a restored session in exactly the same way as requests from a newly logged-in session. Automatic login only restores the session, so the procedure the app server uses to identify users does not change.

When the app client sends ISessionManager.AccessToken to the app server, the app server calls the Hive Axyl Server API with that value to check whether the token is valid and the Player ID of the token's owner. Do not trust the Player ID sent by the app client as is; base your handling on the value that the Hive Axyl server confirms.

If you run your service with only the app client and no app server, you do not need this step.

11. Verify the behavior

  • App code  Verify the behavior in the app.

Check both restoration paths on a real device. The Unity Editor has no device secure storage, so ISecureStorage is not registered, and you cannot verify the save and relaunch flow as is.

  1. After you log in, read the store and check that a StoredSession that is not null is returned.
  2. Quit the app completely, relaunch it, and check for Success and the same PlayerId as when you logged in.
  3. Replace the saved access token with a malformed string and relaunch the app. The recipe cannot read the expiration time and selects the refresh token path, so check that this path also returns Success.
  4. Clear the store, launch the app, and check that NoSession is returned and the login screen appears.

Failure handling

Recipe methods do not throw exceptions; they return a result object. If Status in step 8 is BusinessOutcome, the Hive Axyl server rejected the restoration, so the handling depends on the BusinessOutcome value.

BusinessOutcome Meaning What the app does
InvalidRefreshToken, PlayerNotFound The saved credentials can no longer be used. StoredCredentialIsStale also comes as true, so delete the saved values and show the login screen.
TemporarilyUnavailable At the token issuance step, the Hive Axyl authentication server temporarily could not access its internal storage and could not make a decision, and the request left no effect. This is the only token issuance result that you can retry. Do not call again immediately; call again with the same values, increasing the interval with each attempt. The app decides the interval.
AppIdMismatch The App ID that issued the saved tokens differs from the App ID of the current build. Do not delete the saved values; check the build's App ID.
AppNotFound, InvalidClient The server does not recognize the App ID or Client ID that the app sent. Do not delete the saved values; check the App ID and Client ID in the Hive Console.
UnsupportedGrantType The server does not support the recipe's token issuance method. There is no value the app can fix. Record the error, and then show the login screen.
IpBlocked, ServiceTerminated The server rejected the request according to its policy. Do not delete the saved values; inform the user of the situation.
InvalidGatewayContext The gateway did not accept the call information of the request. Do not display it to the user; record it, and then show the login screen.
InvalidAuthorizationCode, ExpiredAuthorizationCode, CodeChallengeMismatch Token issuance during restoration was rejected. Do not delete the saved values; show the login screen. The refresh token may already have been consumed, so do not call again automatically.
Unrecognized A response that this recipe does not translate. Handle it as a failure and record it, and do not infer it as a known value.
Do not call again with the same refresh token just because the call failed

The Hive Axyl authentication server replaces the refresh token with a new value each time it is used and invalidates the previous value. The only exception is TemporarilyUnavailable, which you can retry; if you call again with the same value after any other failure, that call is also rejected.

Unrecognized covers two situations. If UnknownOutcomeCode has a value, the server sent a response that the current SDK build does not know; if it is empty, the SDK knows the response, but the recipe has not carried it over yet. Use both values, together with RawJson, only for error logging, and do not display them to the user.

For the result model and handling principles when Status is Failure, see Common error handling.

Next steps

To delete the saved credentials when the user leaves the app, see the Logout practical guide.