'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 1:[1]
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
Solution 2:[2]
I haven't tested this but have applied this technique in past.
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)
})
function GoogleAuth() {
useEffect(() => {
const src = 'https://accounts.google.com/gsi/client'
loadScript(src)
.then(() => {
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
)
})
.catch(console.error)
return () => {
const scriptTag = document.querySelector(`script[src="${src}"]`)
if (scriptTag) document.body.removeChild(scriptTag)
}
}, [])
//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
Solution 3:[3]
you can use https://www.npmjs.com/package/@react-oauth/google, and you can check the implementation https://github.com/MomenSherif/react-oauth if you want to implement on your own
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | bogdanoff |
Solution 3 | Mo'men Sherif |