azureunity-game-enginefirebase-authenticationmsal

How to use Microsoft authentication via Firebase in Unity


I am trying to use Firebase in Unity(after unsuccessfully trying to get MSAL for Android working within Unity for B2C. Currently, Firebase lets me do a regular email + password register and log in. But when I try to use the Microsoft sign-in feature the app just flashes for a second, my debugger gets detached, and then nothing happens. Any ideas what could be going wrong?

    public void SignInWithMicrosoft()
    {
        StartCoroutine(SignInWithMicrosoftAsync());
    }

    private IEnumerator SignInWithMicrosoftAsync()
    {
        var signInTask = auth.SignInWithProviderAsync(provider);

        yield return new WaitUntil(() => signInTask.IsCompleted);
        
        if (signInTask.Exception != null)
        {
            Debug.LogError("SignInWithProviderAsync encountered an error: " +
                           signInTask.Exception);
        }
        else
        {
            AuthResult authResult = signInTask.Result;
            FirebaseUser user = authResult.User;
            Debug.LogFormat("User signed in successfully: {0} ({1})",
                user.DisplayName, user.UserId);
        }
    }

Tried stripping the provider data down to the bare minimum, and checked to make sure provider contents were valid. I expect it to open a browser(as it states on the Firebase docs) with the Microsoft sign-in.


Solution

  • Solved it(but also went back to Azure B2C) For those that might be looking into this kind of thing in the future here's the Firebase issue I had and also how to do stuff with B2C in Android:

    Firebase: My issue was I had to add the SHA-1 and SHA-256 to the firebase console, and also I had forgotten to enable microsoft sign in in the console(so I was just being silly). After that it was opening but I got an error after logging in, didn't go any further than that sorry

    Azure B2C: This one was a bit more convoluted. Things you'd have to do:

    you'll then have to do a bunch of JNI stuff to interface with it(its a bit annoying, but it'll look something like this in the end:

    public class MSALAndroid
        {
            public AndroidJavaObject publicClientApplication;
        
            public string accessToken;
            public TaskCompletionSource<string> tcs;
        
            public MSALAndroid(string clientId, string authority, string redirectUri)
            {
                using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                using (AndroidJavaObject applicationContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext"))
                using (AndroidJavaClass publicClientApplicationClass = new AndroidJavaClass("com.microsoft.identity.client.PublicClientApplication"))
                {
                    publicClientApplicationClass.CallStatic("create",
                        applicationContext,
                        clientId,
                        authority,
                        redirectUri,
                        new MSALApplicationCreatedListener(this));
                }
            }
        
            public Task<string> AcquireToken(string[] scopes)
            {
                tcs = new TaskCompletionSource<string>();
                try
                {
                    using (AndroidJavaObject scopeArray = new AndroidJavaObject("java.util.ArrayList"))
                    {
                        foreach (string scope in scopes)
                        {
                            scopeArray.Call<bool>("add", scope);
                        }
                        using (AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
                        using (AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"))
                        {
                        
                            object[] parameters = new object[3];
                            parameters[0] = currentActivity;
                            parameters[1] = scopes;
                            parameters[2] = new MSALCallback(this);
                            publicClientApplication.Call("acquireToken", parameters);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug.Log("Error: " + ex.Message);
                }
        
                return tcs.Task;
            }
        }
        
        public class MSALCallback : AndroidJavaProxy
        {
            private MSALAndroid msalAndroid;
            public MSALCallback(MSALAndroid msalAndroid) : base("com.microsoft.identity.client.AuthenticationCallback")
            {
                this.msalAndroid = msalAndroid;
            }
            
            public void onSuccess(AndroidJavaObject authenticationResult)
            {
                // Handle successful authentication.
                // You can call authenticationResult.Call<string>("getAccessToken") to get the access token.
                msalAndroid.accessToken = authenticationResult.Call<string>("getAccessToken");
                Debug.Log("ACCESS TOKEN: " + msalAndroid.accessToken);
                
                msalAndroid.tcs.SetResult(msalAndroid.accessToken);
            }
        
            public void onError(AndroidJavaObject msalException)
            {
                var exception = msalException.Call<string>("getMessage");
                Debug.Log(exception);
                // Handle error.
            }
        
            public void onCancel()
            {
                // Handle cancellation.
            }
        }
        
        public class MSALApplicationCreatedListener : AndroidJavaProxy
        {
            private MSALAndroid msalAndroid;
        
            public MSALApplicationCreatedListener(MSALAndroid msalAndroid) : base("com.microsoft.identity.client.IPublicClientApplication$ApplicationCreatedListener")
            {
                this.msalAndroid = msalAndroid; 
            }
        
            public void onCreated(AndroidJavaObject application)
            {
                // Handle successful creation here.
                msalAndroid.publicClientApplication = application;
                Debug.Log("Application created!");
            }
        
            public void onError(AndroidJavaObject exception)
            {
                // Handle error here.
            }
        }
    

    this code hasn't been tidied up and probably can be improved, but just wanted it out there since I suffered way too much for it