Search code examples
javascriptreactjsgoogle-identity

React Google Identity services


I have been trying to implement Google's identity services API in my React app, but couldn't get it to work.

I'm trying to implement the following really simple JS code: https://developers.google.com/identity/gsi/web/guides/display-button#javascript

What I came up with is the following:

  useEffect(() => {
    //I'm adding the <script>
    const elemScript = document.createElement('script'); 
    elemScript.src = "https://accounts.google.com/gsi/client";
    elemScript.async = true;
    elemScript.defer = true;
    document.body.append(elemScript);

    //adding the code from the documentation
    window.onload = function () {
      /*global google*/
      console.log(google)
      google.accounts.id.initialize({
        client_id: "<don't worry, I put the ID here>",
        callback: handleCredentialResponse
      });
      google.accounts.id.renderButton(
        googleButton.current, //this is a ref hook to the div in the official example
        { theme: "outline", size: "large" }  // customization attributes
      );
    }

    return () => {
      //I get ride of the <scripts> when the elements is unmounted
      document.body.removeChild(elemScript);
    }
  }, [])

  //This is my main and only objective, to get the token...
  function handleCredentialResponse(response) {
    console.log("Encoded JWT ID token: " + response.credential);
  }

  return (
    <div ref={googleButton}></div>
  )
}

export default GoogleAuth

When I call this component in my main App it sometimes renders the button, sometimes it doesn't (and the cause of this seems to be react-router-dom as it won't load if I'm moving from another page in my domain to where the button is). And even when I get the render I get errors and I can't login.

Thanks to Bogdanof's answer solved the problem of the button only appearing sometimes through the use of Promises.

Now my only problem is the following:

[GSI_LOGGER]: The given origin is not allowed for the given client ID.

I have made and ID OAuth2.0 on Google only for this App. I enabled http://localhost:3000 as it's JS origin (and the same for the URIs), but I'm still getting that answer. I tried changing browsers and even deleting my cache and cookies as I read that it may help, but nothing worked.

Someone has any ideas about how to solve this?


Solution

  • Hey so I got the final result, the following code doesn't has any problem with rendering the button thanks to the use of Promises (again thanks bogdanoff for his help with this):

    //External imports
    import { useEffect, useRef } from 'react'
    
      const loadScript = (src) =>
      new Promise((resolve, reject) => {
        if (document.querySelector(`script[src="${src}"]`)) return resolve()
        const script = document.createElement('script')
        script.src = src
        script.onload = () => resolve()
        script.onerror = (err) => reject(err)
        document.body.appendChild(script)
      })
    
    const GoogleAuth = () => {
    
      const googleButton = useRef(null);
    
      useEffect(() => {
        const src = 'https://accounts.google.com/gsi/client'
        const id = "< your ID here ;) >"
    
        loadScript(src)
          .then(() => {
            /*global google*/
            console.log(google)
            google.accounts.id.initialize({
              client_id: id,
              callback: handleCredentialResponse,
            })
            google.accounts.id.renderButton(
              googleButton.current, 
              { theme: 'outline', size: 'large' } 
            )
          })
          .catch(console.error)
    
        return () => {
          const scriptTag = document.querySelector(`script[src="${src}"]`)
          if (scriptTag) document.body.removeChild(scriptTag)
        }
      }, [])
    
      function handleCredentialResponse(response) {
        console.log("Encoded JWT ID token: " + response.credential);
      }
    
      return (
        <div ref={googleButton}></div>
      )
    }
    
    export default GoogleAuth
    

    Then for solving the OAuth problem I found the solution here in Crow's answer: The given origin is not allowed for the given client ID (GSI)

    Basically add http://localhost without a port to your origins (dunno why gsi needs this, but it needs it)

    Hope this helps someone