Search code examples
oauthgoogle-oauthopenid-connect

Relationship between Google Identity Services - Sign In with Google and User Authorization for Google APIs


I'm studying the Google document on "Google Identity Services" and seem to see two stories. One is called "Sign in With Google" which presents an attractive button where a user can sign-in with their Google account. The other is the Google Identity Services Authorization which grants an access token to make API calls.

What I am missing is whether or not there is a relationship between these two concepts/SDKs/functions. My mind is saying that I want a pretty button on my web page that I can use to sign in (ala Sign in With Google) AND I want the click of that button to give me an access token that I can use to invoke Google APIs. What I seem to be finding is that they are separate and discrete concepts with no obvious relationship between them. Is that correct?

References

2022-06-26: Following a post from Blunt, I tried to add a hint but that didn't seem to make a difference. Here is the code I have been using. First, the index.html that loads the test:

<!DOCTYPE html>
<html>
<body>

    <script src="https://accounts.google.com/gsi/client"></script>
    <script src="./index.js"></script>
    <div id="g_id_onload" data-client_id="XXX.apps.googleusercontent.com"
        data-callback="handleToken" data-auto_prompt="false">
    </div>
    <div class="g_id_signin" data-type="standard" data-size="large" data-theme="outline" data-text="sign_in_with"
        data-shape="rectangular" data-logo_alignment="left">
    </div>
</body>
</html>

and the JavaScript loaded in index.js

const clientId = "XXX.apps.googleusercontent.com"
function handleToken(x) {
  debugger;
  const client = google.accounts.oauth2.initTokenClient({
    client_id: clientId,
    hint: "myemailaddress",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
    callback: (response) => {
      debugger;
    },
  });
  client.requestAccessToken();
}

What I am finding is that I get a the button in the web page as desired ... I click the button, I am prompted to sign in to Google and then the debugger statement (the first one) in the handleToken function is reached. The code progresses and then I am prompted to sign in to Google a second time. It had been my hope that the first sign-in would have been sufficient and somehow context would be preserved for the authorization.


Solution

  • In the new Google Identity Service, the authentication (sign-in) and authorization (access to api's) are separated, but not entirely distinct.

    I have an article that explains this, and a reference implementation for pure client-side solution. npm install gothic will get you that reference implementation.

    But here are the details:

    (1) The sign-in with Google gives you the pretty button. Signing in provides user information encoded in a JWT. But none of this provides an access token.

    (2) To obtain the authorization, you need to drive a second, sequential process. To expedite this process you can use the email address from the sign in process as an optional hint parameter to the authorization library, but the first time the user accesses it, they will still need to go through an explicit authorization process, depending on what api's (scopes) you need to access.

    With regard to authorization, there are two models:

    (1) Token-based. This is the pure client-side version. With this, you ultimately provide your clientId, your API-key, the discovery uri and the scopes to the library, and you get back a 1-hour token, that authorizes use of the APIs your app needs. As I mentioned, this requires an explicit prompt to the user the first time, and is click-free thereafter. But you will need to renew that token every hour, or on each page refresh.

    (2) Code-based. This requires you to have a server-side to your app as well. In this model, your client obtains a code from Google, and hands that to your server. Your server exchanges it for an access token and a refresh token, and thereafter uses the refresh token to obtain new access tokens.

    The server-side, code-based model is the more secure, and can ultimately provide the better UX, but it is of course more architecturally complex.

    If you have specific code you are trying to get working, feel free to share and we can help.