Token Null with Player Accounts

Hello. I’m running into an issue with Player Accounts and tokens. When the game starts I initialize gaming service and call the StartSignInAsync function. The window pops up and I sign in, everything seems successful. The issue comes when I try to pull some cloud save data. My cloud save pull was working when I was just signing in anonymously but since I’ve added the Player Account sign in I’m getting an error (CloudSaveException: Access token is missing).

I spent some time reviewing the Player Accounts sample to see what I was doing wrong and I realized that when I tried to use the ‘refresh token’ button in the sample scene I was getting an error there too (PlayerAccountsException: Refresh token is null or empty).

Given that I didn’t change anything in the sample scene and I’m getting the error I’m inclined to believe I have some kind of mistaken in my project setup but I have no idea what it would be. I have some of my code below. I greatly appreciate any assistance.

private async void Start()
    {
        await UnityServices.InitializeAsync();
        signInWithUnity();
        PlayerAccountService.Instance.SignedIn += signInWithUnity;
    }

    async void signInWithUnity()
    {
        if (!PlayerAccountService.Instance.IsSignedIn)
        {
            try
            {
                await PlayerAccountService.Instance.StartSignInAsync();
                Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
                Debug.Log(AuthenticationService.Instance.AccessToken);
                GetComponent<BattlePassCode>().checkPurchaseStatusOnCloud();
            }
            catch (AuthenticationException ex)
            { Debug.LogException(ex); }
            catch (RequestFailedException ex)
            { Debug.LogException(ex); }
        }
    }
    public async void checkPurchaseStatusOnCloud()
    {
        Dictionary<string, string> savedData = await CloudSaveService.Instance.Data.LoadAsync(new HashSet<string> { "hasBattlePass" });

        if (savedData.ContainsKey("hasBattlePass"))
        {
            if (savedData["hasBattlePass"] == "true")
            { purchased = true; }
        }
    }

Hello,

You are missing the part where you login to the Authentication service using the Player Account token.
They are two separate systems that can be used together or independently.

Steps:
1- Login to Unity Player Account, similar to logging in to google/apple/etc
2- Login to Authentication Service using Player Account token similar to other providers
3- Use Unity Gaming Services like cloudsave, economy, etc.

Step 2 should look like:

AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken)

Let me know if this helps.

Thanks for the quick response Erick. Unfortunately I’m still having issues. I tried rolling your code into mine and I’m getting more errors. Perhaps I’m not putting this in the right place (this area is a stretch of my coding ability). The issue seems to be that after successfully completing step 1 (logging into the unity player account), the PlayerAccountService.Instance.IdToken is still null. So what I have now is:

    async void signInWithUnity()
    {
        if (!PlayerAccountService.Instance.IsSignedIn)
        {
            try
            {
                await PlayerAccountService.Instance.StartSignInAsync();
                Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
                AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.IdToken);
            }
            catch (AuthenticationException ex)
            { Debug.LogException(ex); }
            catch (RequestFailedException ex)
            { Debug.LogException(ex); }
        }
    }

The debug is returning null and then I get this error: [Authentication]: Request failed: 400, {“title”:“INVALID_PARAMETERS”,“detail”:“external token not provided”,“details”:[ ],“status”:400}

Why are you providing the IdToken and not the AccessToken in AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.IdToken)?

You are correct, that was a typo. I corrected this but I’m still getting the same error.

    async void signInWithUnity()
    {
        if (!PlayerAccountService.Instance.IsSignedIn)
        {
            try
            {
                await PlayerAccountService.Instance.StartSignInAsync();
                Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
                AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
            }
            catch (AuthenticationException ex)
            { Debug.LogException(ex); }
            catch (RequestFailedException ex)
            { Debug.LogException(ex); }
        }
    }

I ran a debug after the StartSignInAsync() and it showed that the AccessToken was null

Hello,

I noticed you’re checking the IsSignedIn property and not handling the event which ensures that sign in was successful. To ensure that the access token has returned after signing-in via browser you need to subscribe to and handle the PlayerAccountService.Instance.SignedIn event in your code.

An example of what that should look like:
PlayerAccountService.Instance.SignedIn += YourMethodName;

Documentation : Unity Player Accounts

If you check his first post, then you see that he does so in the Start() method. I would also handle it differently and separate the different actions taken to not have sign in calls and validation in the same method.

Appreciate the continued assistance. As MiTschMR said, I am calling that exact code in my start function, which seems to be how the documentation suggests. If it should be in the actual sign in function I can certainly move it but some quick testing seems to run into the same error either way.

Thanks for pointing that out. When the SignedIn event is triggered IsSignedIn should be true, can you remove the if (!PlayerAccountService.Instance.IsSignedIn) check in your code and try if that works? Since you’re checking if its false its likely not executing the rest of your code.

Ok, I’ve done that. See updated code below.

    private async void Start()
    {
        await UnityServices.InitializeAsync();
        signInWithUnity();
        PlayerAccountService.Instance.SignedIn += signInWithUnity;
    }

    async void signInWithUnity()
    {
            try
            {
                await PlayerAccountService.Instance.StartSignInAsync();
                Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
            AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
            }
            catch (AuthenticationException ex)
            { Debug.LogException(ex); }
            catch (RequestFailedException ex)
            { Debug.LogException(ex); }
    }

Unfortunately I’m still getting the same authentication request failed error. I’m additionally getting a PlayerAccountsException because it’s trying to login twice now, which is why I had put the !isSignedIn check in initially.

I think the issue here is that your signInWithUnity function is being used both as the method to start the sign-in process and as the event handler for the SignedIn event.

Here’s a revised version of your code that separates the two concerns (It’s not tested but you can get the idea) :

 private async void Start()
    {
        await UnityServices.InitializeAsync();
        StartSignIn();
        PlayerAccountService.Instance.SignedIn += OnSignedIn;
    }

    private async void StartSignIn()
    {
        try
        {
            await PlayerAccountService.Instance.StartSignInAsync();
        }
        catch (AuthenticationException ex)
        {
            Debug.LogException(ex);
        }
        catch (RequestFailedException ex)
        {
            Debug.LogException(ex);
        }
    }

    private void OnSignedIn()
    {
        Debug.Log("Player Account Access token " + PlayerAccountService.Instance.AccessToken);
        AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
    }

Let me know if this helps!

1 Like

saadk_unity, this worked! Thank you so much. I don’t know that I’d have ever been able to solve it otherwise.