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

Question AccesToken Null after signing in Player Accounts

Discussion in 'Authentication' started by vengefullfoot, Jul 17, 2023.

  1. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    Hi,

    I'm signing in Player Accounts using the method StartSignInAsync() considering the player never signed in before.
    As I'm testing the feature I don't get any exception but PlayerAccountService.Instance.AccessToken is null.
    From my different testing, it looks like itis linked to the fact I first connect to the cached player using
    SignInAnonymouslyAsync(). This also happens if I signout just before trying to signin to Player Accounts.

    How should I proceed if I want to add Unity Player account to my cached user in that case ?

    Thank you in advance
     
  2. MiTschMR

    MiTschMR

    Joined:
    Aug 28, 2018
    Posts:
    358
    If I understood correctly, you need to check, if the cached user has any other linked account providers. If it does not, then you can offer the link with UPA. If it does, then you don't show it. The linked providers are on the AuthenticationService side, not on UPA side.
     
  3. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    That's not exactly it. Here is the workflow:
    - check if there is a cache user
    - if yes connect it
    - check identities, show unity player accounts login button if not in the identities

    In the current case, no external provider yet, so I show a "login with Unity" button that triggers
    await PlayerAccountService.Instance.StartSignInAsync(); (like in the demo code)
    But here no error, no PlayerAccountService.Instance.AccessToken. I've tried to sign out from authentication service before sigining in Player Account, does change the fact I don't get that Accesstoken to link the account in a following step
     
  4. MiTschMR

    MiTschMR

    Joined:
    Aug 28, 2018
    Posts:
    358
    But the StartSignInAsync() call opens up a browser window for the user to sign up / sign in with email and password?
     
  5. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    Hello,
    Could you please share the code you're using for signing in and querying the access token, which results in a null token so we have more details?
    Thanks
     
  6. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    Yes, there is the browser window, everything is going fine when I authenticate there, but still the access token is null and isSignedIn false.
     
  7. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    It's difficult to tell without looking at the code. Something to check:

    StartSignInAsync() is an asynchronous function and the sign-in process may not be completed immediately. Trying to access the token right after this call might result in a null value, as the sign-in process in the browser may not have finished.

    Are you subscribing to and appropriately handling the PlayerAccountService.Instance.SignedIn event in your code? This event is crucial to ensure that you query the access token only after the sign-in process has successfully completed.

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

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31

    Yes I'm doing that, but actually the SignedIn event is not happening. So I guess something is going wrong, but I have no error message and no exception raised on the call and the login page in browser says "done, you can go back to..."

    I'm preparing an extract of the code to help you diagnosing it.
     
  9. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    It's a bit difficult to give a full view as I'm separting each external provider into a separate feature. Here are some parts of the code:

    Code (CSharp):
    1.    protected async void OnEnable()
    2.     {
    3.        OnValueChanged(unityLoginFeatureVariable);
    4.         unityLoginFeatureVariable.OnValueChanged += OnValueChanged;
    5.         PlayerAccountService.Instance.SignedIn += SignedIn;
    6.     }
    7.  
    8.     private void OnDisable()
    9.     {
    10.         unityLoginFeatureVariable.OnValueChanged -= OnValueChanged;
    11.         PlayerAccountService.Instance.SignedIn -= SignedIn;
    12.     }
    13.  
    14.     private async void OnValueChanged(bool value)
    15.     {
    16.         unityLoginUIButton.gameObject.SetActive(value);
    17.         if (value)
    18.         {
    19.             if (UnityServices.State != ServicesInitializationState.Initialized)
    20.             {
    21.                 await UnityServices.InitializeAsync();
    22.             }
    23.         }
    24.     }
    25.  
    26.     public async void Login()
    27.     {
    28.         // there is already a token
    29.         try
    30.         {
    31.             if (playerInfo.Value.unityToken == "")
    32.             {
    33.                 // SignOut();
    34.                 //var token = PlayerAccountService.Instance.AccessToken;
    35.                 infoText.text = "Connecting...";
    36.                 await PlayerAccountService.Instance.StartSignInAsync();
    37.             }
    38.             else
    39.             {
    40.                 infoText.text = "Connecting with Token...";
    41.                 await AuthenticationService.Instance.SignInWithUnityAsync(playerInfo.Value.unityToken);
    42.             }
    43.         }
    44.         catch (AuthenticationException ex)
    45.         {
    46.             // Compare error code to AuthenticationErrorCodes
    47.             // Notify the player with the proper error message
    48.             Debug.LogException(ex);
    49.             infoText.text = "Unity Exception " + ex.Message;
    50.         }
    51.         catch (RequestFailedException ex)
    52.         {
    53.             // Compare error code to CommonErrorCodes
    54.             // Notify the player with the proper error message
    55.             Debug.LogException(ex);
    56.             infoText.text = "Unity Exception " + ex.Message;
    57.         }
    58.     }
    59.  
    60.     private void SignedIn()
    61.     {
    62.         playerInfo.Value.unityToken = PlayerAccountService.Instance.AccessToken;
    63.         infoText.text = "Connected to Unity ";
    64.         checkDataEC.RaiseEvent();
    65.     }
    66.  
    67.  
    68.     /// <summary>
    69.     /// Signs the player out.
    70.     /// </summary>
    71.     void SignOut()
    72.     {
    73.         AuthenticationService.Instance.SignOut();
    74.     }
    75.  
     
  10. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    Solved,
    I moved

    Code (CSharp):
    1. PlayerAccountService.Instance.SignedIn += SignedIn;
    into :

    Code (CSharp):
    1. private async void OnValueChanged(bool value)
    2.     {
    3.         unityLoginUIButton.gameObject.SetActive(value);
    4.         if (value)
    5.         {
    6.             if (UnityServices.State != ServicesInitializationState.Initialized)
    7.             {
    8.                 await UnityServices.InitializeAsync();
    9.                 PlayerAccountService.Instance.SignedIn += SignedIn;[
    10.             }
    11.         }
    12.     }
    As it looks like PlayerAccountService.Instance.SignedIn is assigned only once UnityServices are initialized, which for some reason was the already the case at that moment...
     
  11. vengefullfoot

    vengefullfoot

    Joined:
    Sep 24, 2018
    Posts:
    31
    One more question :

    Is this making sense ?
    Code (CSharp):
    1. if (playerInfo.Value.unityToken == "")
    2.             {
    3.                 // SignOut();
    4.                 //var token = PlayerAccountService.Instance.AccessToken;
    5.                 infoText.text = "Connecting...";
    6.                 await PlayerAccountService.Instance.StartSignInAsync();
    7.             }
    8.             else
    9.             {
    10.                 infoText.text = "Connecting with Token...";
    11.                 await AuthenticationService.Instance.SignInWithUnityAsync(playerInfo.Value.unityToken);
    12.             }
    As it looks like the accessToken is only valid for the "session" (not sure it's the exact name in this context). In that case the "else" part will always use an "old" token, which will make the AuthenticationService.Instance.SignInWithUnityAsync fails due to the outdated token ?
     
  12. saadk_unity

    saadk_unity

    Unity Technologies

    Joined:
    Oct 15, 2021
    Posts:
    12
    That's correct, access token is only valid for the session, once the session ends or the token expires, you cannot use the same access token to sign in again.

    Instead, you should initiate a new sign-in process using StartSignInAsync(). This will provide a new access token for the session.

    Essentially sign-in only needs to happen once to obtain the Player Accounts access token. Once you have signed into the Authentication Service using SignInWithUnityAsync, the session token within the Authentication Service keeps the session alive.