8

I'm migrating from the old Google Sign In library to the new Google Identity Services (GIS) library. This is mandatory, since the old one will no longer be in use from March 2023.

Previously, I did (simplified for clarity):

<script src="https://apis.google.com/js/api:client.js"></script>
gapi.load();
var auth2 = gapi.auth2.init();
auth2.attachClickHandler();
onGoogleSignIn(googleUser); // attachClickHandler's callback
var profile      = googleUser.getBasicProfile(); // profile info accessible
var authResponse = googleUser.getAuthResponse(); // auth response accessible
var accessToken  = authResponse.id_token; // get actual access token

Now, I'm trying (simplified for clarity):

<script src="https://accounts.google.com/gsi/client"></script>
var gisClient = google.accounts.oauth2.initTokenClient();
gisClient.requestAccessToken();
callback(); // initTokenClient's callback
var accessToken = response.access_token; // get access token in callback

With the old google sign in library, I validated the access token server side as such:

Payload payload = await GoogleJsonWebSignature.ValidateAsync(accessToken);

This also returned the user's email and name in the payload.

The access token I am getting back from GIS, is much shorter than the old one from GAPI.

An online token debugger tells me it's not a valid JWT token.

The ValidateAsync method throws an exception:

JWT must consist of Header, Payload, and Signature

No surprise, considering it's not a valid JWT token.

I also tried the following call:

Payload payload = await JsonWebSignature.VerifySignedTokenAsync(AccessToken, options);

Same result.

The official documentation doesn't say how to validate this token server side for C# / .NET.

I can't find help on this anywhere in the documentation.

What can I do to get server side access token validation (and retrieval of email + profile) working with Google Identity Services?

Jay
  • 740
  • 4
  • 8
  • 19
  • What exactly are you trying to verify? One of your links is on how to verify the Id token. Yet you talk of access token. – Linda Lawton - DaImTo Mar 22 '22 at 13:05
  • var accessToken = authResponse.id_token; <-- storing an id token in variable called access token is gong to cause a lot of confusion down the road. – Linda Lawton - DaImTo Mar 22 '22 at 13:07
  • Yeah, I'm just trying things. I don't usually do much with google's APIs and have little experience with them. I don't understand this token-stuff as well as I'd like. I have a SAAS that uses Google sign-in. I am forced to migrate to GIS. I would like to get back a token that can be validated server side, whereby I also get back the user's name and email in the payload. Calling 'authResponse.id_token' in GoogleJsonWebSignature.ValidateAsync() worked. Calling 'response.access_token' in GoogleJsonWebSignature.ValidateAsync() does not. – Jay Mar 22 '22 at 13:09
  • Yes, I see that I've been calling an id token an access token. Was not aware that I was doing that until now. I guess I better study up on the difference. Any source you can point me at, for gaining a better understanding, will be appreciated. A suggested solution to what I'm trying to accomplish, as well. – Jay Mar 22 '22 at 13:10
  • Which Nuget package are you using exactly I want to be sure where on the same page. – Linda Lawton - DaImTo Mar 22 '22 at 13:11
  • To begin with you are confusing somethings. GIS is identity (id token) Oauth2 is For use with google apis (access token) – Linda Lawton - DaImTo Mar 22 '22 at 13:12
  • My Nuget package is: https://www.nuget.org/packages/Google.Apis.Auth/1.56.0. – Jay Mar 22 '22 at 13:13
  • that's not Gis though, thats google apis. I thought you were using some new library for Gis. Where is that? – Linda Lawton - DaImTo Mar 22 '22 at 13:14
  • Wait your authorizing using JavaScript, and you want to verify that token server side? Why not just do it client side why send a token to server side? – Linda Lawton - DaImTo Mar 22 '22 at 13:15
  • I don't understand how identity tokens, access tokens, oauth2 and google APIs all relate. All I know is I have to migrate to GIS for doing my sign ins. The documentation says so. I manage to get a google login popup with GIS. It returns something. Seems to me that I should somehow be able to retrieve email + profile with it on the server side. That's the info I store for account creation/login via google. – Jay Mar 22 '22 at 13:15
  • To see which library I'm using now, see the old js script and the new js script in the OP. I assume I am validating server side because that's what I learned to do from the old documentation (t's been a while since I built my current google sign in). If it's so weird to validate server side, then why is that functionality offered at all? – Jay Mar 22 '22 at 13:18
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/243184/discussion-between-daimto-and-jay). – Linda Lawton - DaImTo Mar 22 '22 at 13:20
  • @DaImTo , any updates on this ? – yasseros Jul 10 '22 at 07:20
  • 1
    I also posted this on [GitHub](https://github.com/googleapis/google-api-nodejs-client/issues/2921). The answer seems to be to use the People API. – Jay Jul 14 '22 at 11:27
  • 1
    Answer is the same as its on git. You validate the id token not the access token. var accessToken = authResponse.id_token; why are you renaming an id token to access token. Its not an access token its an id token. You can NOT validate an access token in this manner. You can only validate an id token. – Linda Lawton - DaImTo Jul 14 '22 at 15:54
  • DaImTo, my previous comment was directed at @yasseros, who asked for updates on this. I am aware that the access/id token confusion was always an error on my part. I'll be sure to fix it when I pick up this migration again in the near future. – Jay Jul 15 '22 at 15:58

1 Answers1

6

Explanation

The new Google Sign in returns "CredentialResponse" which contains a property called credential, which is the JSON Web Token (JWT) in base64 that you need.
This JWT can be sent to client or server for validation.
After validation you will receive user profile data.

Client

<div id="g_id_onload"
     data-client_id="YOUR_GOOGLE_CLIENT_ID"
     data-callback="handleCredentialResponse">
</div>
<script>

    function handleCredentialResponse(response) {

        //get JSON Web Token (JWT) out of the response object
        var jwt = response.credential;

        //send JWT to backend server for validation
        var result = ValidateAtServer(jwt);

        //do something with result
        KillUserInstantly(result);
    }
</script>

Server (.NET)

public static void ValidateAtServer(httpRequest)
{
  //get jwt string from request
  ...

  //validate it using Google.Apis.Auth (null if invalid)
  var validPayload = await GoogleJsonWebSignature.ValidateAsync(jwtToken);

  //get user data & use it
  var userId = validPayload.Subject; //The unique ID of the user's Google Account
  var email = validPayload.Email;

  //do something with data
  ...
}

Beginner Notes

  1. "unique user ID" in located under subject or sub
  2. "ID token" is the base64-encoded JSON Web Token (JWT) string.
  3. Validating the JWT also decrypts the data inside which includes user profile.

Example JWT/ID Token

eyJhbGciOiJSUzI1NiIsImtpZCI6IjE1NDllMGFlZjU3NGQxYzdiZGQxMzZjMjAyYjhkMjkwNTgwYjE2NWMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2NTk3NTk0MzEsImF1ZCI6IjEwODgwNjIxNjM1NzMtaXMwdWQ1aDRza2JscmR1Njp0cnVlLCJheuZXMiLCJpYXQiOjE2NTk3NTk3MzEsImV4cCI6MTY1OTc2MzMzMSwianRpIjoiMDhlNjRhM2I1YzdmNzcxYmRjNTg5M2YwNmMyZjM1ZWZlMzIyNjYyMCJ9.UT07_-_4o_1D5NmVAI0QtXLupVZtXys3Kg0c--Cv-xrMpUZXInfqj142eojvTEf6QBmBPY3k-Mtu7djJAenB8Ed8-dWtvFdGdv5FdSJCSyLN70ObzCsdo_IgjG5r3HTw1C9pIFKggOklJrVN-zL0_Kh3TZdxfMdyEbAUuhIRCreUVgZ74XEWhR6x4l0EY9o2331HcrzAaie_LN4C8NVHhkQ0DLg5dO2v8T1uKG-eTyv-uvjMuhkSVBJR3MnvkGepj7o0h_ELGO9x74P9nNjIKTyZboEr4_YO0BP5aLPwt67LJHactAJ8DJTzugXwaJBVhusK1KPYYGRhy7nTfbfTSg
user160357
  • 865
  • 10
  • 14
  • 2
    To those new to Google Sign In, this does take time to wrap your head around. But once you understand the basics, it becomes quite simple. Google docs can help: https://developers.google.com/identity/gsi/web/guides/handle-credential-responses-js-functions – user160357 Aug 06 '22 at 04:03
  • Thanks a lot. Using the HTML-API code generator, I managed to get a HTML/code snippet just like yours. The login is working. I am successfully validating the JWT and getting the Google user ID in return. But now I need to use the people API to request the user's email and profile pic. The example documentation seems simple enough. But nowhere does it show how it gets an instance of 'peopleService': https://developers.google.com/people/v1/profiles#.net. How to acquire an instance of a peopleService? – Jay Sep 06 '22 at 16:10
  • So, apparently, you create a new PeopleServiceService, and you pass in a BaseClientService.Initializer() call into its constructor. But the PeopleServiceService also requires some type of GoogleCredential to be set to the HttpClientInitializer property. Is it possible to acquire such a GoogleCredential from the JWT and the validated payload of it? – Jay Sep 06 '22 at 18:39
  • From decoding the JWT on jwt.io, I can see that it's got the info I need in there. Just like you said, @user160357. Now to find out how to decode that JWT on the server side, because the validation call isn't returning the decoded result. That means I won't have to figure out the People API anymore. It used to be that I also got the scopes values back from a login response. I would store those for reference. The decoded JWT doesn't have the scopes, though. If only I can figure out how to request those without a hassle, as well. – Jay Sep 06 '22 at 18:55
  • I'm building my Google login button in Vue. It helps to use the JS API, instead of the HTML API. The JS API reference can be found here: https://stackoverflow.com/questions/71757310/sign-in-with-google-gis-on-vue-js-application. – Jay Sep 07 '22 at 14:08
  • 1
    I managed to build the best possible solution for my use case by combining the answers given in this thread, as well as this reply on another thread: https://stackoverflow.com/a/73518135/1018165. GIS is easy to work with, once you get the hang of it. My only beef with it, is that you don't get to define your own button. And Google's rendered button doesn't let you have full control over its width, since you can't set min/max width. – Jay Sep 07 '22 at 14:11