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.
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 autorize 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 (promt).
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'})
})
})