Unity Player Accounts WebGL build Can't Login 'Unity.Services.Authentication.PlayerAccounts.IBrowserUtils.Bind' on type '' failed

Hello all, I’m new to unity and game making. I have been working on my first project for a long while now learning as I go. My game is near complete and I’m trying to get the unity player accounts authentication to work for my webGL build. Everything works properly in the editor but when I post the game on Github or do a build and run it wont let me authenticate. I get this error ‘Unity.Services.Authentication.PlayerAccounts.IBrowserUtils.Bind’ on type ‘’ failed.
I have tried multiple iterations of my login/authentication script. All packages are updated. I originally started building with Version 2021.3.1f1, which did not work so I have also tried version 6000.0.28f1 with no luck as well.

My coding is ugly to begin with and with the multiple iterations has gotten worse but here is is…

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Services.Core;
using Unity.Services.Authentication;
using Unity.Services.Authentication.PlayerAccounts;//
using System.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System;
using System.Text;
//using Unity.Notifications.Android;
//using Unity.Notifications.iOS;


//namespace Unity.Services.Authentication.PlayerAccounts
//{


public class LM : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI ExceptionText;
    [SerializeField] private TextMeshProUGUI StatusText;
    [SerializeField] public TextMeshProUGUI PlayerIDText;
    [SerializeField] private TextMeshProUGUI PlayerNameText;
    [SerializeField] private TMP_InputField PlayerNameFieldText;
    [SerializeField] private TextMeshProUGUI EmailText;
    [SerializeField] private TMP_InputField EmailFieldText;

    string m_ExternalIds;

    public GameObject loginScreen;
    public GameObject loginScreenBG;//
    public GameObject notificationScreen;//
    [SerializeField] public TextMeshProUGUI notificationText;//
    public bool notificationAcknowledged = false;//
    public GameObject uPScreen;
    public GameObject DRText;
    public GameObject WPText;

    public bool signedInToAuthenticator;
    public bool signedInToPlayerAccount;
    public bool logOut;
    private bool GameLoaded;
    public static bool gameIsLoading;
    public long lastNotificationDate;

    public GameObject loadProgress;
    public Slider slider;
    public TextMeshProUGUI progressText;

    public void LoadGameBeforeSceneChange()
    {
        CloudSaveManager.LoadPlayerData1();
        CloudSaveManager.LoadPlayerData2();
        CloudSaveManager.LoadPlayerDataAfterShop1();
        CloudSaveManager.LoadPlayerDataAfterShop2();
        CloudSaveManager.LoadPlayerDataAfterShop3();
        CloudSaveManager.LoadPlayerDataAfterShop4();
    }

    public void InputUsername()
    {
        //PlayerPrefs.SetString("playername", PlayerNameFieldText.text);
        PlayerData.PlayerName = PlayerNameFieldText.text;
    }

    public void InputEmail()
    {
        PlayerData.Email = EmailFieldText.text;
    }

    public void GoToMainMenu()
    {
        PlayerNameText.text = AuthenticationService.Instance.PlayerName;
        PlayerData.Email = EmailFieldText.text;
        PlayerData.TimesLoggedIn += 1;
        PlayerData.Save();
        SceneManager.LoadScene("Main Menu");
    }


    async void Awake()
    {
        try
        {
            await UnityServices.InitializeAsync();
            PlayerAccountService.Instance.SignedIn += SignInWithUnity;
            //PlayerAccountService.Instance.SignedIn += SignInWithUnity;
        }
        catch (Exception ex)
        {
            Debug.LogException(ex);
        }

        //logOut = MainMenu.wantToLogOut;
        //if (logOut)
        //{
        //    SignOut();
        //}
     
    }

    public async void StartSignedInAsync()
    {
        if (PlayerAccountService.Instance.IsSignedIn)
        {
            SignInWithUnity();
            return;
        }

        try
        {
            await PlayerAccountService.Instance.StartSignInAsync();
        }
        catch (RequestFailedException ex)
        {
            Debug.LogException(ex);
            SetException(ex);
        }
    }


    async void SignInWithUnity()
    {
        if (signedInToAuthenticator)
        {
            Debug.LogWarning("Sign-in already in progress. Please wait.");
            return;
        }

        List<Unity.Services.Authentication.Notification> notifications = null;

        try
        {
            await AuthenticationService.Instance.SignInWithUnityAsync(PlayerAccountService.Instance.AccessToken);
            m_ExternalIds = GetExternalIds(AuthenticationService.Instance.PlayerInfo);
            signedInToAuthenticator = true;
            Debug.Log($"PlayerID: {AuthenticationService.Instance.PlayerId}");
            Debug.Log("SignIn is Successful");
            PlayerData.PlayerID = AuthenticationService.Instance.PlayerId;
            CloudSaveManager.LoadTimesLoggedIn();
            CloudSaveManager.LoadLastReadNotificationDate();
            await Task.Delay(2000); //time in millisecond

            string lastNotificationDateString = AuthenticationService.Instance.LastNotificationDate;
            long storedNotificationDate = PlayerData.LastReadNotificationDate;
            //Debug.Log(lastNotificationDateString);
            //Debug.Log(storedNotificationDate);

            if (!string.IsNullOrEmpty(lastNotificationDateString) && long.TryParse(lastNotificationDateString, out long lastNotificationDate))
            {
                if (lastNotificationDate > storedNotificationDate)
                {
                    // Retrieve the notifications from the backend
                    notifications = await AuthenticationService.Instance.GetNotificationsAsync();
                    if (notifications != null)
                    {
                        PlayerData.LastReadNotificationDate = lastNotificationDate;
                        CloudSaveManager.SaveLastReadNotificationDate();
                        await DisplayNotifications(notifications);//
                                                                  //DisplayNotifications(notifications);
                    }
                    else
                    {
                        Debug.Log("There are no new notifications");
                    }
                }
            }

            if (PlayerData.TimesLoggedIn >= 1)
            {
                LoadGameBeforeSceneChange();
                StartCoroutine(loadMainMenuProgress());
            }
            else
            {
                SetStatsForFirstTimePlaying();
                loginScreen.SetActive(false);
                DRText.SetActive(false);
                WPText.SetActive(false);
                uPScreen.SetActive(true);
            }

            UpdateUI();

        }

        catch (AuthenticationException ex)
        {
            Debug.LogException(ex);
        }

        catch (RequestFailedException ex)
        {
            Debug.LogException(ex);
            SetException(ex);

            // Handle sign-in failure and check for notifications
            //if (ex is AuthenticationException authEx && authEx.Notifications != null)
            //{

               // await DisplayNotifications(authEx.Notifications);
            //}
        }
    }
public void SignOut()
    {
        AuthenticationService.Instance.SignOut();

        if (logOut)
        {
            //SAVE ALL GAME DATA HERE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            PlayerAccountService.Instance.SignOut();
            signedInToPlayerAccount = false;
            MainMenu.wantToLogOut = false;
            logOut = false;
            //PlayerAccountService.Instance.SignOut();
        }


        UpdateUI();
    }


    public void CancelSignIn()
    {
        logOut = true;
    }

    public void OpenAccountPortal()
    {
        Application.OpenURL(PlayerAccountService.Instance.AccountPortalUrl);
    }

    

    async Task DisplayNotifications(List<Unity.Services.Authentication.Notification> notifications)
    {
        loginScreen.SetActive(false);
        loginScreenBG.SetActive(false);
        notificationScreen.SetActive(true);

        foreach (var notification in notifications)
        {
            notificationAcknowledged = false;
            notificationText.text = notification.Message;
            //Debug.Log("Displaying notification: " + notification.Message);
            await WaitForNotificationAcknowledge();
            //Debug.Log("Notification acknowledged, continuing to next notification");
        }
    }
    async Task WaitForNotificationAcknowledge()
    {
        Debug.Log("Waiting for notification to be acknowledged");
        while (!notificationAcknowledged)
        {
            await Task.Yield();
        }
        Debug.Log("Notification acknowledged, continuing");
    }


    public void ClickedNotificationWasRead()
    {
        PlayerData.LastReadNotificationDate = lastNotificationDate;
        CloudSaveManager.SaveLastReadNotificationDate();
        notificationAcknowledged = true;

    }

    void SaveLastNotificationReadDate()
    {

        PlayerData.LastReadNotificationDate = lastNotificationDate;
    }

    void UpdateUI()
    {
        var statusBuilder = new StringBuilder();

        statusBuilder.AppendLine($"Player Accounts State: <b>{(PlayerAccountService.Instance.IsSignedIn ? "Signed in" : "Signed out")}</b>");
        statusBuilder.AppendLine($"Player Accounts Access token: <b>{(string.IsNullOrEmpty(PlayerAccountService.Instance.AccessToken) ? "Missing" : "Exists")}</b>\n");
        statusBuilder.AppendLine($"Authentication Service State: <b>{(AuthenticationService.Instance.IsSignedIn ? "Signed in" : "Signed out")}</b>");

        if (AuthenticationService.Instance.IsSignedIn)
        {
            statusBuilder.AppendLine(GetPlayerInfoText());
            statusBuilder.AppendLine($"PlayerId: <b>{AuthenticationService.Instance.PlayerId}</b>");
        }

        StatusText.text = statusBuilder.ToString();
        SetException(null);
    }

    string GetExternalIds(PlayerInfo playerInfo)
    {
        if (playerInfo.Identities == null)
        {
            return "None";
        }

        var sb = new StringBuilder();
        foreach (var id in playerInfo.Identities)
        {
            sb.Append(" " + id.TypeId);
        }

        return sb.ToString();
    }

    string GetPlayerInfoText()
    {
        return $"ExternalIds: <b>{m_ExternalIds}</b>";
    }


    void SetException(Exception ex)
    {
        ExceptionText.text = ex != null ? $"{ex.GetType().Name}: {ex.Message}" : "";
    }


    IEnumerator loadMainMenuProgress()
    {
        yield return new WaitForSeconds(2f);
        PlayerData.TimesLoggedIn += 1;
        AsyncOperation operation = SceneManager.LoadSceneAsync("Main Menu");


        loadProgress.SetActive(true);

        while (operation.isDone == false)
        {
            float progress = Mathf.Clamp01(operation.progress / .9f);

            slider.value = progress;
            progressText.text = progress * 100f + "%";

            yield return null;
        }
    }

Can someone please help me figure this out. Thank you very much.

This should be a sticky, really. For one, the use of Task.Delay within a sequence of code is not just bad, it’s TERRIBLE PRACTICE! You cannot expect an async task to complete within a given time frame, you need to use exception handling to deal with any timeouts that may occur. Any other reasons to delay something, start a coroutine that waits instead.

But most importantly:

Task.Delay() is NOT supported in WebGL!

I saw the thread and first thing I did was to search for it. Found it, noted it. I am not saying that this is the cause of your particular issue, but it will be an issue regardless and chances are high that it is the cause.

Task.Delay will await infinitely if I recall correctly. Delaying a task requires threading support which is not available in web builds.

Thanks for the reply. I removed the delay and will figure out another way. I only put the delay there to make sure that the data was loaded before continuing on.

Unfortunately this did not fix my issue. I’m still getting the same error.

I know I read in a couple discussions that Unity Player Accounts Authentication was not working for WebGL builds yet. That it was still being developed but on the back burner. But then I have also seen a couple where people have said that it is working for them.

Guess I will keep trying to figure it out for a little longer. May have to give up on UPA and UGS and see if I can do it will Firebase or something else. Will take a lot more effort to redo everything but at least maybe I can get it working. Seem to be more tutorials and stuff for other services than for UGS.

For the heck of it I changed it and built it as a standalone game for windows. Authentication worked fine and I was able to login and play. Does that mean the Unity player account authentication does not work with webGL builds currently??? Is it still broken? Can anyone confirm if it is working or broken with WebGL builds?

I have the same issue.
I have followed the tutorial of the offical manual:
Empty project, only the official sample imported using package manager.
Editor and PC build OK, runs perfectly.
WebGL fails:

Firefox
“RuntimeError: index out of bounds”
Edge
“RuntimeError: memory access out of bounds”

(Note for anyone who would like to try, there is bug in the sample scene, two GameObjects are using the PlayerAccountsDemo script, but one of them has no input link. So the script runs twice in async, and cause sign in issue like already signed in or so…)