How to use the new Google API with scopes?

447 views Asked by At

For a uni project, I was attempting to create a simple demo React app that would fetch some data from a Google Account – first the basic stuff, like name and avatar, but then "scoped data" from Google Fit API. Note: The app cannot function without the scopes, they are all required at the very first screen.

The first part took around 10 minutes, but the second part took me several hours and I got absolutely nowhere. I read the How user authorization works and the entire Authorizing for Web section, but I just ended up with nothing – I may know what the authorization code model is, but how do I code it? Where do I put the code? How can I call Google Fit API afterwards?

Maybe there is some resource that I missed that explains this?

Most things I tried by the usual method – scour the internet or ask GPT – ended in "You have created a new client application that uses libraries for user authentication or authorization that are deprecated." I was able to make the login button with two variants, one getting an access_token and the other credentials:

The first was using useGoogleLogin method from @react-oauth/google which gave me an access_token. As soon as I defined scope though, the login failed and popup wrote "Something went wrong, please try again" or smth.

const signIn = useGoogleLogin({
     clientId: GOOGLE_CLIENT_ID,
     redirect_uri: 'http://localhost:3000',
     ux_mode: 'redirect',
     onSuccess: setCred, // useState setter
     onError: (err) => console.error('Google Error:', err),
     onFailure: (err) => console.error('Google Error:', err),
     //scope: 'https://www.googleapis.com/auth/fitness.activity.read',
});

Then I tried following this tutorial on YouTube, which gave me credentials – from which I was able to get profile information. That was nice, but that was the end of it. According to the docs, logging in (authentication) and permissions (authorisation) are two separate things, and I did not get any successes with the latter.

useEffect(() => {
  /* global google */
  google.accounts.id.initialize({
       client_id: GOOGLE_CLIENT_ID,
       callback: (res) => {
            if (res.error)
                 return console.error('Google Error:', res.error);
            console.log(res);
            setCred(res.credential); // useState setter
       },
  });

  google.accounts.id.renderButton(
       document.querySelector('#google-login'),
       {
            theme: 'outline',
            size: 'large',
       }
  );
}, []);

I tried playing around with a dedicated backend with googleapis as read somewhere, but those attempts all got nowhere – my params never quite matched what Google wanted.

1

There are 1 answers

0
Danry On

So I also had this problem recently while trying to make a web app without a backend (just using @tanstack/react-query and calling APIs purely on the frontend), from which I also stumbled upon the @react-oauth/google package.

I managed to make the implicit flow work by using the access_token like so:

const login = useGoogleLogin({
  scope: [
    "openid",
    "https://www.googleapis.com/auth/userinfo.profile",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/calendar.readonly",
  ].join(" "),

  onSuccess: setAuth,
})

// Somewhere in the app
const url = "https://www.googleapis.com/calendar/v3/colors" // example
const response = await fetch(url, {
  headers: {
    // ...
    Authorization: `Bearer ${auth.access_token}`,
  },
})

Relevant GH issue where the package owner explains some important stuff: https://github.com/MomenSherif/react-oauth/issues/12#issuecomment-1131408898

As for the error when adding the scope, maybe you incorrectly configured your Google Cloud OAuth consent screen somewhere?

Also, in case you missed it, you can go here for a better understanding of the auth flows: https://react-oauth.vercel.app/