7

I'm using Google One-Tap sign in to authenticate users, and after the user is authenticated I get an access token. I know that I can use this access token in order to work with the Google API client for JavaScript ("GAPI"). But I can't find any way to work with GAPI using this access token.

Is there any way to use GAPI assuming I already have an logged in user?

What I'm trying to do is access the user calendar after simply authenticating with One-Tap authentication and giving consent for the calendar once.

mesqueeb
  • 5,277
  • 5
  • 44
  • 77
  • Once you signed in using gapi and asked the user for consent, then you can use the calendar api to get the user's calendar information. You can take a look at this link https://developers.google.com/google-apps/calendar/quickstart/js – Wen W Feb 25 '18 at 04:15
  • you will need an api key, client id, and set the scope for consent. Google is the one that remembers the user has given consent, the user can also revoke at anytime in their google profile. – Wen W Feb 25 '18 at 04:16
  • @WenHaoWu Thanks! As you mention everything works if I use `gapi` to authenticate the user from the beginning. The problem is that I want to use Google One-Tap authentication. This is causing problems as I don't know how to make GAPI initialized/authenticated in the case the user is authenticated through Google One-Tap auth... – mesqueeb Feb 25 '18 at 04:23
  • have you tried using the same gapi code after Google One-Tap authentication? Something like auth2 = gapi.auth2.getAuthInstance(); if(auth2.isSignedIn.get()){ let googleUser = auth2.currentUser.get(); let id_token = googleUser.getAuthresponse().id_token;} – Wen W Feb 25 '18 at 04:36

1 Answers1

14

First of all:
There is no way to "authenticate" the google JS api client with the response that is returned by the One-Tap sign in.

Luckily we don't need to authenticate with the gapi JS client because we use a handy function called gapi.auth2.authorize!

How to authorize the gapi client

It's important to first read the docs and understand their warning:

Do not use this method alongside the recommended gapi.auth2.init and signIn flow. These are two distinct behaviors (Authorization for gapi.auth2.authorize vs Authentication for gapi.auth2.init/signIn) and will have unexpected issues if used within the same application.

Now the question is how to completely avoid the init/signIn method.

Step 1
Sign the user into the Google One-Tap sign in.

Step 2
Load the gapi client: window.gapi.load('client')

Step 3
Pass the credential.id (the email address) returned by Google One-Tap as the login_hint param in the call to authorize. This will preselect the account and we can try to not show any new login pop-up (prompt).

Example:

gapi.auth2.authorize({
  client_id,
  prompt: 'none',
  response_type: 'permission', // Access Token.
  scope: 'CALENDAR_SCOPE',
  login_hint: credential.id
}, function(result) {})

Using prompt: 'none', you can try to fetch a token without any UI. This is useful to check whether you need to show an Authorize button, and also useful before making any call to the Calendar API to get a fresh token.

Step 4
Before we can make any call to gapi.client.calendar we need to initialize the client with just the calendar discoveryDocs.

gapi.client.init({discoveryDocs})

This is the most tricky part and is not properly documented anywhere! The only thing we can retrieve from the api.client.init() documentation is the following line:

If OAuth client ID and scope are provided, this function will load the gapi.auth2 module to perform OAuth

This basically means: as soon as you give either clientID or scope gapi.client.init will try and start the traditional authentication method.
In our case: we don't need to pass the clientID or scope as we've already done this in step 3.

So how does the client know which module to initialize? → By only passing the discoveryDocs of the module you want to use! In this case the calendar discoveryDocs.

Step 5
Now you're done! You can make requests with e.g. gapi.client.calendar.events.list()


Full example

A full code example can be found here below:

const config =  {
  response_type: 'permission',
  scope: 'CALENDAR_SCOPE',
  client_id: clientId,
  login_hint: credential.id,
  promt: 'none',
}
gapi.auth2.authorize(config, function(response) {
  // No need to `setToken`, it's done for you by auth2.
  let calConfig = {discoveryDocs} // only of google calendar
  window.gapi.client.init(calConfig).then(function() {
    // then execute a calendar call:
    window.gapi.client.calendar.events.list({'calendarId': 'primary'})
  })
})
maudulus
  • 10,627
  • 10
  • 78
  • 117
mesqueeb
  • 5,277
  • 5
  • 44
  • 77
  • Masqueeb: Thanks. This works like a charm when user access token is valid i.e .one hour. This fails when we try after one hour or user logs out. Is there any way to get new access token? – Ashis Nov 13 '19 at 13:33