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

Viewed 232

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.

2 Answers

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.

To start with you need to understand the difference between two concepts.

Authentication and authorization.

authorization

Authorization is the act by which a user who owns private data grants an application created by a developer to access their data. Authorization is requested by showing a consent screen. A user consents to the application accessing their data, the amount of access a user grants is designated by the scopes requested.

In the image below the application Google Oauth 2.0 Playground is asking me for permission to See and download all my google drive files.

enter image description here

I requested the "https://www.googleapis.com/auth/drive.readonly" scope when requesting authorization.

Authorization is Oauth2. it returns an access token and a refresh token. Access tokens can be used to access api endpoints. In this case the google drive api. Access tokens are short lived and expire after an hour. The refresh token can be used to request a new access token at any time when the user is off line. This is why there is no way for an api to see if the entity preforming the call is actually the user who owns the data, it may infact be a third party application using an access token and refresh token to gain access to the users data.

You can grant an application access to your data and they can continue to request your data until you revoke that access.

Authentication

Authentication on the other hand is sign in. It is prof that the what made the call is in fact the user who owns the account. They must have typed their user name and password or logged into their account. Or already be logged into their google account on their machine. If you have two google accounts signed in like I do they you will be promoted for which user you would like to use.

So authencation authenticates or proves, that the user making the call is in fact the owner of the account the data resides on. Authentication is something called Open Id connect and was built on top of Oauth2.

The scope that are email, profile, and openid either profile or openid is required email is optional. Open id connect basically gives you access to a users profile information. If you are using a library you wont normally see this scope its normally added internally. If the only scope that is requested is a open id connect scope then the user will not see a consent screen. In the call above I added profile scope so you can see it is also asking for access to profile data but its grayed out the user cant not accept it.

enter image description here

Open id connect returns something called an id token. the id token is very short lived its around five minutes. An id token is a jwt so you can use jwt.io to decrypt it. Within the jwt you can find a number of claims. This claims give your application information about who the user is that just signed into your system.

Of note, name, picture, locale (language), and sub, sub is the users internal user id on the calling authentication server. So you can use the google sub id to link this users google account to your internal user storage. Then when ever this user logs in using google you will know which user it is in your system by matching the id.

{
  "iss": "https://accounts.google.com",
  "azp": "40740878192.apps.googleusercontent.com",
  "aud": "407408718192.apps.googleusercontent.com",
  "sub": "1172004532672775346",
  "at_hash": "Aa0FT7DLf38T_onVI_ca8g",
  "name": "Linda Lawton",
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GhroCYJp2P9xeYeYk1npchBPK-zbtTxzNQo0WAHI20=s96-c",
  "given_name": "Linda",
  "family_name": "Lawton",
  "locale": "en",
  "iat": 1656311886,
  "exp": 1656315486
}

Note.

Sign-in will not grant you an access token unless you are able to add additional scopes to it, like drive, or calendar. I have yet been able to figure out how to add additional scopes to googles new JavaScript web login library.

The thing is what exactly are you trying to do. Do you want to log a user into your system. Or do you just want access to some private user data of theirs through one of googles apis?

Related