CrossGeeks / GoogleClientPlugin

Google Client Plugin for Xamarin iOS and Android
https://www.pujolsluis.com/google-client-plugin-for-xamarin/
MIT License
89 stars 37 forks source link

idToken and accessToken are null #56

Closed husseinshaib1 closed 4 years ago

husseinshaib1 commented 4 years ago

hi, I am trying to get the idtoken and accessToken but both are null. I followed the documentation and initialized the plugin with client id but no success. any suggestions?

kylewhittington commented 4 years ago

I'm having the same issue. Bizarrely, I had this working a couple nights ago, but as of this evening both idToken and accessToken are null after authenticating, but CurrentUser is populated, as well as IsLoggedIn showing 'true'.

Did you figure it out @husseinshaib1?

husseinshaib1 commented 4 years ago

@kylewhittington yes I've got everything working fine. share some code to check of you are missing something.

kylewhittington commented 4 years ago

Code for the method that does authentication below. I'm using Firebase for authentication after the fact -- ie. Google login first, then exchange access token for a Firebase JWT. However, the access token is not populated when coming back from the Google auth, with a 'completed' status.

The strange this is that implementation was almost certainly working a few days ago. Of course outside of this I have the google-services.json in the project (and checked it is up to date), and I am initialising the plugin within the MainActivity after OnCreate.

Why would GoogleService not yet have those values populated, when authentication is over? What did you find was wrong with yours?

Any help is much appreciated!

private async Task ExecuteLoginWithGoogleCommand()
        {
            IsBusy = true;

            try
            {
                if (_googleService.IsLoggedIn)
                {
                    _googleService.Logout();
                }

                EventHandler<GoogleClientResultEventArgs<GoogleUser>> userLoginDelegate = null;
                userLoginDelegate = async (object sender, GoogleClientResultEventArgs<GoogleUser> e) =>
                {
                    switch (e.Status)
                    {
                        case GoogleActionStatus.Completed:
#if DEBUG
                            var googleUserString = JsonConvert.SerializeObject(e.Data);
                            Debug.WriteLine($"Google Logged in succesfully: {googleUserString}");
#endif
                            var currenUser = _googleService.CurrentUser; // This is populated
                            var idToken = _googleService.IdToken; // This is null
                            var accessToken = _googleService.AccessToken; // This is null
                            var isLoggedIn = _googleService.IsLoggedIn; // This is true
                            var credentials = await FirebaseAuthService.LoginWithGoogle(accessToken);
                            if (credentials.AccessToken != null)
                            {
                                await AccountStore.SaveCredentialsAsync(credentials);                                
                                App.GetMainPage();
                            }
                            else
                            {
                                Dialogs.Toast("We were unable to log you in using your Google account. Something went wrong.");
                            }
                            break;
                        case GoogleActionStatus.Canceled:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Canceled", "Ok");
                            break;
                        case GoogleActionStatus.Error:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Error", "Ok");
                            break;
                        case GoogleActionStatus.Unauthorized:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Unauthorized", "Ok");
                            break;
                    }

                    _googleService.OnLogin -= userLoginDelegate;
                };

                _googleService.OnLogin += userLoginDelegate;

                await _googleService.LoginAsync();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }

            IsBusy = false;
        }
brugner commented 4 years ago

Same issue here, this is my code.

var result = await CrossGoogleClient.Current.LoginAsync();

if (result.Status == GoogleActionStatus.Completed)
{
    string token =  CrossGoogleClient.Current.IdToken);
}

I think I've followed all the steps correctly. What could possibly be wrong? @husseinshaib1 any ideas?

husseinshaib1 commented 4 years ago

here is the code I am usign:

`var response = await CrossGoogleClient.Current.LoginAsync(); switch (response.Status) { case GoogleActionStatus.Completed: IGoogleClientManager _googleService = CrossGoogleClient.Current;

                    string googleIdToken = _googleService.IdToken;
                    string googleAccesstoken = _googleService.AccessToken;

                    var firebaseToken = await DependencyService.Get<IFacebookAuthenticatorR>().GetFirebaseTokenFromgoogleCredentials(googleIdToken, googleAccesstoken);
                    this.ManageLogin(firebaseToken);
                    break;
                case GoogleActionStatus.Canceled:
                    await App.Current.MainPage.DisplayAlert("Google Auth", "Canceled", "Ok");
                    break;
                case GoogleActionStatus.Error:
                    await App.Current.MainPage.DisplayAlert("Google Auth", "Error", "Ok");
                    break;
                case GoogleActionStatus.Unauthorized:
                    await App.Current.MainPage.DisplayAlert("Google Auth", "Unauthorized", "Ok");
                    break;
            }`

`public async Task LoginWithFacebookOrAndroid(object credential) { try {

            IAuthResult user = await FirebaseAuth.Instance.SignInWithCredentialAsync(credential as AuthCredential);

            //var instanceIdResult = await FirebaseInstanceId.Instance. .GetInstanceId().AsAsync<IInstanceIdResult>();
            //var refreshtoken = instanceIdResult.Token;

            var token = user.User.GetIdToken(false);
            //Tasks.await(token);

            Firebase.Auth.GetTokenResult tokenResult = token.Result as Firebase.Auth.GetTokenResult;

            return tokenResult.Token;

        }
        catch (FirebaseAuthInvalidUserException e)
        {
            e.PrintStackTrace();
            return "";
        }
    }`

also make sure that in firebase console you are specifying the sha-1 for the keystore you are using to sign the apk. let me know if there is still any issue

kylewhittington commented 4 years ago

OK, I've discovered a couple things.

Without initialising the GoogleClientManager with your ClientId, you won't get the idToken back. There is documentation here about that here: https://github.com/CrossGeeks/GoogleClientPlugin/blob/master/docs/GettingStarted.md -- under the 'Enabling Server Auth Code or RequestIdToken Programmatically (Optional)' which is why I previously skipped it.

However, the main reason you can't access the AccessToken straight after it is authenticated has got to do with a slightly async thing happening in the background which takes a few hundred milliseconds to return, and is thus not yet populated. This is terrible but to hack this all you have to do is sleep the thread by a few hundred milliseconds (I did 500). I believe it's because of this line:

https://github.com/CrossGeeks/GoogleClientPlugin/blob/7e13ed59b3a3c49ec95809a3ff07b862ca6dab2c/src/Plugin.GoogleClient/GoogleClientManager.android.cs#L252

I believe if this code was changed to run sync rather than pushing into a new task, then it would follow through without having to do the delay. Not sure what the implications of that are, but I'm pretty sure that is why we're seeing this issue.

I have no idea why @husseinshaib1's is working without this!

My updated code below:

private async Task ExecuteLoginWithGoogleCommand()
        {
            IsBusy = true;

            try
            {
                if (_googleService.IsLoggedIn)
                {
                    _googleService.Logout();
                }

                EventHandler<GoogleClientResultEventArgs<GoogleUser>> userLoginDelegate = null;
                userLoginDelegate = async (object sender, GoogleClientResultEventArgs<GoogleUser> e) =>
                {
                    switch (e.Status)
                    {
                        case GoogleActionStatus.Completed:
#if DEBUG
                            var googleUserString = JsonConvert.SerializeObject(e.Data);
                            Debug.WriteLine($"Google Logged in succesfully: {googleUserString}");
#endif                                                       
                            await Task.Delay(500);
                            var accessToken = _googleService.AccessToken;
                            var credentials = await FirebaseAuthService.LoginWithGoogle(accessToken);
                            if (credentials.AccessToken != null)
                            {
                                await AccountStore.SaveCredentialsAsync(credentials);
                                App.GetMainPage();
                            }
                            else
                            {
                                Dialogs.Toast("We were unable to log you in using your Google account. Something went wrong.");
                            }
                            break;
                        case GoogleActionStatus.Canceled:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Canceled", "Ok");
                            break;
                        case GoogleActionStatus.Error:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Error", "Ok");
                            break;
                        case GoogleActionStatus.Unauthorized:
                            await App.Current.MainPage.DisplayAlert("Google Auth", "Unauthorized", "Ok");
                            break;
                    }
                    _googleService.OnLogin -= userLoginDelegate;
                };

                _googleService.OnLogin += userLoginDelegate;

                await _googleService.LoginAsync();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }

            IsBusy = false;
        }
rdelrosario commented 4 years ago

Please try on latest version should be fixed