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?
Advertisement
Answer
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