0

Recreation of error experience: I click on the Google sign-in button on my web app that calls the login function posted below. It prompts a simple popup for the user to sign in with a Google account. After that, in chrome console, I see the following Max stack error:

RangeError: Maximum call stack size exceeded

I copied the code from the firebase docs: https://firebase.google.com/docs/auth/web/google-signin

This is part of an old project that I'm deciding to improve. There were a lot of outdated vuetify codes etc that I cleaned up, and I moved local data to vuex. I also made sure to cleanup the move to vuex. There shouldn't be any problem with vue side.

I have researched the RangeError a little on Google and here, I saw that using firebase database's snap on client side causes this error. My case should be different from that case, imo.

The google account that I'm using has an existing account (through email account creation), however this shouldn't be the cause of this problem since:

  1. the doc says Google and gmail accounts will merge without any error iirc (I set firebase to have 1 account per email)
  2. the RangeError was the error message returned on console. So 1. is irrelevant.

I did read the Firebase reference page, but this error isn't discussed there.

To clarify, I'm not seeing the user/token set console message in chrome, i.e. the promise returns the error only.

I'll be happy to receive any suggestions or solution to this problem. Thanks in advance.

Below is my login function:


    login({ commit, dispatch }) {
      return new Promise(function(resolve, reject) {
        const provider = new firebase.auth.GoogleAuthProvider();
        provider.addScope('email');
        provider.addScope('profile');
        firebase.auth().signInWithPopup(provider).then((result) => {
          // The signed-in user info.
          commit(
            'setUser',
            result.user,
          );
          console.log('user set');
          // This gives you a Google Access Token. You can use it to access the Google API.
          commit(
            'setToken',
            result.credential.accessToken,
          );
          console.log('token set');
          return resolve();
          // ...
        }).catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const { email } = error;
          // The firebase.auth.AuthCredential type that was used.
          const { credential } = error;
          console.error('error found during login');
          console.error('---------error');
          console.error(error);
          console.error(errorCode);
          console.error(errorMessage);
          console.error(email);
          console.error(credential);
          console.error('error---------');
          dispatch('snackbar/queueSnack',
            {
              color: 'error',
              msg: errorMessage,
            },
            { root: true });
          return reject(error);
        });
      });
    },

Edit: I made login action return a promise. It didn't help.

Edit 2: The error was actually caused by lack of 'sameSite' attribute. I initially missed/ignored the warning:

A cookie associated with a cross-site resource at http://google.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/00000000 and https://www.chromestatus.com/feature/00000000000000.

According to https://github.com/firebase/firebase-js-sdk/issues/2284, the issue is with Google API not setting the sameSite attr. Firebase doesn't handle any cookies. I'll look into this tomorrow.

Edit 3: I thought disabling sameSite feature from chrome://flags will fix this. It didn't. The comment sharing how to disable sameSite in the firebase github issue was deleted. Now I'm going to use Google API to login Google.

Remember that gapi only deals with pure html/javascript. I was annoyed at first thinking vuejs only deals with node packages, but I ultimately remembered of the public/index.html page. It took me longer than needed to remember that. So now all script tags and meta tags can go there and it should be easy to follow Google API docs

1 Answer 1

0

This error was caused by the sameSite feature introduced by Google in 2019 and implemented around july 2020. I read an online article but google it if you're interested. I looked at this firebase issue page on github for more context: https://github.com/firebase/firebase-js-sdk/issues/2284

So just disabling sameSite feature on the page gotten by typing chrome://flags didn't solve this.

The solution is to use Google API's oAuth2 to login to google, then login to firebase using credentials. Follow the steps here: https://developers.google.com/identity/sign-in/web/sign-in. And remember to add the meta and script tags on your public/index.html page. This is such a basic thing that it's easy to forget. I also read how to implement Google Login API in VueJS? and updated my code to look like the code in solution to avoid any global function. The difference is: the onsuccess attribute is not on div tag, but called during mounted().

Now we are able to login to Google API. Don't forget to login to firebase using credentials. See the manual signin part: https://firebase.google.com/docs/auth/web/google-signin


public/index.html

<meta name="google-signin-client_id" content="${replace-with-CLIENT_ID}.apps.googleusercontent.com">
<script src="https://apis.google.com/js/platform.js" async defer></script>

@/components/Header.vue

<div id="google-signin-button"></div>

...

  mounted() {
    gapi.signin2.render('google-signin-button', {
      onsuccess: this.onSignIn
    })
  },

methods: {

    onSignIn: function (googleUser) {
      var profile = googleUser.getBasicProfile();
      console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
      console.log('Name: ' + profile.getName());
      console.log('Image URL: ' + profile.getImageUrl());
      console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
    },
},
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.