Email & Password Auth with multiple scenes

Hi, I am looking for some feedback on this before I dive too deep. I have a login screen scene and a game loop scene. I needed Nakama connection on both scenes, initially had some issues with having 2 sessions open at the same time due to opening one connection on the login screen and another one on the game loop scene when moving from login to game. The only option I could find to fix this is to create an instance of my ConnectionManager and just use the instance in the game scene. First time working with Nakama, unity, and c# so are there any problems with my current code or way to improve it before I go further?

public class ConnectionManager : MonoBehaviour
{
    public static ConnectionManager instance;

    // Connection Info
    private string scheme = "http";
    private string host = "*;
    private int port = *;
    private string serverKey = "*";

    // User Info
    // @_username is required only for registration purposes
    private string _username;
    private string _email;
    private string _password;
    private string _passwordConfirmation;


    // PlayerPrefs
    private const string SessionPrefName = "Session";

    // Connections vars
    private IClient _client;
    private ISession _session;
    private ISocket _socket;
    public IApiAccount Account;

    public IClient Client { get; set; }
    public ISession Session { get; set; }
    public ISocket Socket { get; set; }

    // Matchmaking
    private string ticket;

    // Functions
    private void loadGameLoop()
    {
        SceneManager.LoadScene("GameLoop");
    }
    public void setUsername(string username)
    {
        _username = username;

    }
    public void setEmail(string email)
    {
        _email = email;

    }

    public void setPassword(string password)
    {
        _password = password;

    }

    public void setPasswordConfirmation(string passwordConfirmation)
    {
        _passwordConfirmation = passwordConfirmation;
    }

    public async void handleLogin()
    {
        if (_email != null && _password != null)
        {
            try
            {
                // Create a new session
                Session = await Client.AuthenticateEmailAsync(_email, _password, create: false);
                // Store the session so we can restore it later if needed
                PlayerPrefs.SetString(SessionPrefName, Session.AuthToken);



                Socket = Client.NewSocket();
                await Socket.ConnectAsync(Session, true);
                if (Socket.IsConnected == true)
                {
                    Debug.Log("Connection established...");
                }

                loadGameLoop();
            }
            catch (System.Exception e)
            {

                Debug.Log(e);
            }
        }

    }

    // TODO Return error message to UI
    public async void handleRegister()
    {
        try
        {
            // Check if all fields have values
            if (_email != null && _password != null && _passwordConfirmation != null && _username != null)
            {
                // Check if password and password confirmation match
                if (_password != _passwordConfirmation)
                {
                    Debug.Log("Passwords do not match");
                }
                else
                {
                    // Create a new session
                    Session = await Client.AuthenticateEmailAsync(_email, _password, _username);
                    // Store the session so we can restore it later if needed
                    PlayerPrefs.SetString(SessionPrefName, Session.AuthToken);
                    loadGameLoop();
                }
            }
            else
            {
                Debug.Log("All fields are required!");
            }
        }
        catch (System.Exception e)
        {
            Debug.Log(e);

        }
    }

    public async void handleLogout()
    {
        await Client.SessionLogoutAsync(Session);
        SceneManager.LoadScene("Login");
    }

    public async void FindMatch()
    {
        Debug.Log("Finding match...");
        var matchmakingTicket = await Socket.AddMatchmakerAsync("*", 2, 2);
        ticket = matchmakingTicket.Ticket;
    }

    private async void OnReceivedMatchmakerMatched(IMatchmakerMatched matchmakerMatched)
    {
        Debug.Log(matchmakerMatched);
        var match = await Socket.JoinMatchAsync(matchmakerMatched);
        Debug.Log("Own seession id: " + match.Self.SessionId);

        foreach (var presence in match.Presences)
        {
            Debug.Log("Connected user session id: " + presence.SessionId);

        }
    }

    // Awake
    private async void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }


        if (Socket != null && Socket.IsConnected == true)
        {
            Debug.Log("Socket is already connected");
            return;
        }

        Client = new Client(scheme, host, port, serverKey, UnityWebRequestAdapter.Instance);
        // Attempt to restore the session
        var authToken = PlayerPrefs.GetString(SessionPrefName);

        if (!string.IsNullOrEmpty(authToken))
        {
            Debug.Log(authToken);
            var session = Nakama.Session.Restore(authToken);
            // If the session is not expired use it
            if (!session.IsExpired)
            {
                try
                {
                    Session = session;
                    // Open socket for connection
                    Socket = Client.NewSocket();
                    await Socket.ConnectAsync(Session, true);
                    if (Socket.IsConnected == true)
                    {
                        Debug.Log("Connection established...");

                        // TODO fix this
                        if (SceneManager.GetActiveScene().name != "GameLoop")
                        {
                            SceneManager.LoadScene("GameLoop");
                        }
                    }
                }
                catch (System.Exception e)
                {
                    Debug.Log(e);

                }
                Socket.ReceivedMatchmakerMatched += OnReceivedMatchmakerMatched;
            }
        }
    }
    // On unmount
    void OnDisable()
    {
        Debug.Log("Disabled");

        if (Socket != null)
        {
            Socket.ReceivedMatchmakerMatched -= OnReceivedMatchmakerMatched;
        }
    }
}

I think a cleaner way would be to use DontDestroyOnLoad for your ConnectionManager MonoBehavior, so that you are sure that it’s alive between scenes.

When your game loop scene is loaded, if you want to access the ConnectionManager, you can use FindObjectOfType or similar Unity’s built-in methods. Although it’s not that clean, it works for your scenario.

If DontDestroyOnLoad is not set, the ConnectionManager object will be destroyed as the scene changes. Since the game object is destroyed, I’m not sure how the static instance that you created works. For one thing, the variables and the non-built-in MonoBehavior methods will work (like your FindMatch method), but the built-in ones like Awake or OnDisable won’t work since the game object isn’t in the new scene anymore.

It is what I am using, ConnectionManager is on the login screen and I just use its instance in the Game Loop