Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Token Null with Player Accounts

Discussion in 'Authentication' started by metzingerj, Jul 20, 2023.

  1. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    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.

    Code (CSharp):
    1.    
    2.  
    3. private async void Start()
    4.     {
    5.         await UnityServices.InitializeAsync();
    6.         signInWithUnity();
    7.         PlayerAccountService.Instance.SignedIn += signInWithUnity;
    8.     }
    9.  
    10.     async void signInWithUnity()
    11.     {
    12.         if (!PlayerAccountService.Instance.IsSignedIn)
    13.         {
    14.             try
    15.             {
    16.                 await PlayerAccountService.Instance.StartSignInAsync();
    17.                 Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
    18.                 Debug.Log(AuthenticationService.Instance.AccessToken);
    19.                 GetComponent<BattlePassCode>().checkPurchaseStatusOnCloud();
    20.             }
    21.             catch (AuthenticationException ex)
    22.             { Debug.LogException(ex); }
    23.             catch (RequestFailedException ex)
    24.             { Debug.LogException(ex); }
    25.         }
    26.     }
    Code (CSharp):
    1.     public async void checkPurchaseStatusOnCloud()
    2.     {
    3.         Dictionary<string, string> savedData = await CloudSaveService.Instance.Data.LoadAsync(new HashSet<string> { "hasBattlePass" });
    4.  
    5.         if (savedData.ContainsKey("hasBattlePass"))
    6.         {
    7.             if (savedData["hasBattlePass"] == "true")
    8.             { purchased = true; }
    9.         }
    10.     }
     
  2. erickb_unity

    erickb_unity

    Unity Technologies

    Joined:
    Sep 1, 2021
    Posts:
    66
    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:
    Code (CSharp):
    1. AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken)
    Let me know if this helps.
     
    Last edited: Jul 20, 2023
  3. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    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:

    Code (CSharp):
    1.     async void signInWithUnity()
    2.     {
    3.         if (!PlayerAccountService.Instance.IsSignedIn)
    4.         {
    5.             try
    6.             {
    7.                 await PlayerAccountService.Instance.StartSignInAsync();
    8.                 Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
    9.                 AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.IdToken);
    10.             }
    11.             catch (AuthenticationException ex)
    12.             { Debug.LogException(ex); }
    13.             catch (RequestFailedException ex)
    14.             { Debug.LogException(ex); }
    15.         }
    16.     }
    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}
     
  4. MiTschMR

    MiTschMR

    Joined:
    Aug 28, 2018
    Posts:
    355
    Why are you providing the IdToken and not the AccessToken in
    AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.IdToken)
    ?
     
  5. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    You are correct, that was a typo. I corrected this but I'm still getting the same error.

    Code (CSharp):
    1.     async void signInWithUnity()
    2.     {
    3.         if (!PlayerAccountService.Instance.IsSignedIn)
    4.         {
    5.             try
    6.             {
    7.                 await PlayerAccountService.Instance.StartSignInAsync();
    8.                 Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
    9.                 AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
    10.             }
    11.             catch (AuthenticationException ex)
    12.             { Debug.LogException(ex); }
    13.             catch (RequestFailedException ex)
    14.             { Debug.LogException(ex); }
    15.         }
    16.     }
    I ran a debug after the StartSignInAsync() and it showed that the AccessToken was null
     
  6. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    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 : https://docs.unity.com/authenticati...s#Integrate_with_Unity_Authentication_Service
     
  7. MiTschMR

    MiTschMR

    Joined:
    Aug 28, 2018
    Posts:
    355
    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.
     
  8. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    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.
     
  9. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    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.
     
  10. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    Ok, I've done that. See updated code below.

    Code (CSharp):
    1.     private async void Start()
    2.     {
    3.         await UnityServices.InitializeAsync();
    4.         signInWithUnity();
    5.         PlayerAccountService.Instance.SignedIn += signInWithUnity;
    6.     }
    7.  
    8.     async void signInWithUnity()
    9.     {
    10.             try
    11.             {
    12.                 await PlayerAccountService.Instance.StartSignInAsync();
    13.                 Debug.Log("Signed in " + AuthenticationService.Instance.PlayerId);
    14.             AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
    15.             }
    16.             catch (AuthenticationException ex)
    17.             { Debug.LogException(ex); }
    18.             catch (RequestFailedException ex)
    19.             { Debug.LogException(ex); }
    20.     }
    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.
     
  11. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    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) :


    Code (CSharp):
    1.  private async void Start()
    2.     {
    3.         await UnityServices.InitializeAsync();
    4.         StartSignIn();
    5.         PlayerAccountService.Instance.SignedIn += OnSignedIn;
    6.     }
    7.  
    8.     private async void StartSignIn()
    9.     {
    10.         try
    11.         {
    12.             await PlayerAccountService.Instance.StartSignInAsync();
    13.         }
    14.         catch (AuthenticationException ex)
    15.         {
    16.             Debug.LogException(ex);
    17.         }
    18.         catch (RequestFailedException ex)
    19.         {
    20.             Debug.LogException(ex);
    21.         }
    22.     }
    23.  
    24.     private void OnSignedIn()
    25.     {
    26.         Debug.Log("Player Account Access token " + PlayerAccountService.Instance.AccessToken);
    27.         AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
    28.     }
    Let me know if this helps!
     
    Last edited: Jul 21, 2023
  12. metzingerj

    metzingerj

    Joined:
    Dec 23, 2016
    Posts:
    13
    saadk_unity, this worked! Thank you so much. I don't know that I'd have ever been able to solve it otherwise.