Unity Player Accounts Login Every Time

I have recently been playing around with the new Unity Player Accounts package and have finally got to the point where it is working in my code, with one caveat. Every time I close out of the app and reopen it, it prompts the user to log in again. If I select “Google”, it logs me right back in. Not a huge deal but I feel like this is not the intended. Below is the general flow of my setup. I used the scripts from the sample scene:

  • Game on first launch shows login screen with either Unity Auth or Anonymous
  • Both options result in a player pref being created to indicate the first launch occurred, which skips the login selection screen
  • On close out and subsequent boots, anonymous login is started on awake.
  • Unity’s auth windows pops up, you log in, then everything works as before

I assume step 3 is where I went wrong, but the documentation is very brief and this was the only way I could get leaderboards and saves to work with Unity accounts. Do I need to be saving my auth token somewhere locally and calling it back on app launches?

Was looking around for this answer myself but I think I found a solution (with a caveat)

Basically, you want to store the PlayerAccountService.Instance.AccessToken into playerprefs to use to signin next time. This prevents the login window from popping up every time.

Caveat is I have no idea how long that token stays valid for so you need to wrap that in a try/catch to re-sign in when that fails

my code looks something like this

           string _cachedToken = PlayerPrefs.GetString("access_token");
            if (!_cachedToken.IsEmpty())
            {
                try
                {
                    await AuthenticationService.Instance.SignInWithUnityAsync(_cachedToken);
                }
                catch (PlayerAccountsException ex)
                {
                    Debug.LogException(ex);
                    // if sign in using cached token fails, start sign in process again
                    PlayerPrefs.DeleteKey("access_token");
                    await PlayerAccountService.Instance.StartSignInAsync();
                }
            } else
            {
                await PlayerAccountService.Instance.StartSignInAsync();
            }

...
// put this in start or somewhere early

PlayerAccountService.Instance.SignedIn += SignInWithUnity;
...


// code from the sample/tutorial
async void SignInWithUnity()
    {
        // this helper signs in with unity player accounts first and then uses that acces token to sign in to auth
        try
        {
            //set playerprefs here after we login
            PlayerPrefs.SetString("access_token", PlayerAccountService.Instance.AccessToken);
            await AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
             
            Debug.Log("SignIn with ugs is successful. token is " + AuthenticationService.Instance.AccessToken);
        }
        catch (AuthenticationException ex)
        {
            // Compare error code to AuthenticationErrorCodes
            // Notify the player with the proper error message
            Debug.LogException(ex);
        }
        catch (RequestFailedException ex)
        {
            // Compare error code to CommonErrorCodes
            // Notify the player with the proper error message
            Debug.LogException(ex);
        }
    }

Why don’t you check for a session token and use the SignInAnonymously method if one exists? My flow looks like this:

I have the same problem. Every time I use UPA, android never caches the session token. If I go with your flow, it means that the player has to re-login via UPA every time, because the session token is not cached.

Your flows work in the Unity editor, but not on Android device.

Is there a way to get the session token and store it manually? Or maybe this is a bug?

The session token will be cached once your sign in to the authentication service after logging in to UPA.

A simplified version of this would look something like:

    async Task SignInAsync()
    {
        if (AuthenticationService.Instance.SessionTokenExists)
        {
            await AuthenticationService.Instance.SignInAnonymouslyAsync();
        }
        else
        {
            PlayerAccountService.Instance.SignedIn -= OnPlayerAccountSignIn;
            PlayerAccountService.Instance.SignedIn += OnPlayerAccountSignIn;
            await PlayerAccountService.Instance.StartSignInAsync();
        }
    }

    async void OnPlayerAccountSignIn()
    {
        // Make sure this is called after successfully logging in to UPA and the next operation is successful
        await AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
    }

Important to note that the flow where UPA login is called will finish outside of the initial task scope due to relying on the event being triggered.

Does the SignInAnonymouslyAsync put me back into the same account as the UPA one? We have implemented in app purchases and would like to stick to only UPA

Yes, because UPA is a linked identity to the account. If you sign in with UPA, you sign in to the account.

Hi! A follow-up question. After executing

await AuthenticationService.Instance.SignInAnonymouslyAsync();

the
PlayerAccountService.Instance.AccessToken remains null. How to get the access token for the cached player that has been auto logged in using SignInAnonymouslyAsync() ?

You don’t need it. If the user has already linked the account (or signed in with UPA the first time) the account is linked meaning the user does only need to use UPA for signing in if the cached session token is not available. When signing in with the cached session token (to the linked account) all the information is already there.

If you however still need the access token, you need to again do the full sign in flow by calling PlayerAccountService.Instance.StartSignInAsync() etc.

Thanks for a quick answer! It is very helpful!
I wanted to use the access token to validate player’s requests to the backend API. Or should I rather use AuthenticationService.Instance.AccessToken for that?

What backend API, yours? Then yes, the second one is better, because the first one is for UPA only.

Yes, this is my custom backend. Thanks! It is all clear now:)