I have an SPA with Firebase backend and have integrated Google Calendar access.
To be able to authorise a user to use his/her Google Calendar I am using the gapi.auth2.authorize(params, callback)
method. (this as opposed to the regular gapi.auth2.init
and signIn
flow because my users can link multiple Calendar accounts)
Docs: gapi.auth2.authorize
Sometimes the id_token
that is returned from authorize
includes an email address, and sometimes it doesn't.
The id_token which is returned is a long string that can be read on the front end with a JavaScript function like so:
function parseJwt (token) {
let base64Url = token.split('.')[1]
let base64 = base64Url.replace('-', '+').replace('_', '/')
return JSON.parse(window.atob(base64))
}
When I parse the id_token, I am expecting an object including an email
address. However sometimes it doesn't include the email
property at all....
How can I retrieve the user's google calendar email address from this id_token in with JavaScript, so I can save it to the user's firestore DB?
I think that it might be related to the accounts not returning an email being a Google G-Suite account? And the ones that do return the email is a regular gmail account? But I don't know the solution.
PS:
My flow for re-authorisation for return users is to just use the same gapi.auth2.authorize
but with {prompt: 'none', login_hint: 'emailaddress'}
and fill in the user's saved email address. This works fine.
In case you want to authorise the JavaScript client with gapi.auth2.authorize
but also require the email address the user authorised for, be sure to include email
in the scope of the gapi.auth2.authorize(params, callback)
parameters!!
Step 1.
Include in main HTML head:
<script type=text/javascript src="https://apis.google.com/js/api.js" async defer=defer></script>
Step 2.
(once) Load the client:
window.gapi.load('client', callbackFunction)
Important: Only load the client!
Step 3.
(once) Initialise the client for usage of Calendar API.
Important: Only include the discovery docs!
let calDocs = {
discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest']
}
window.gapi.client.init(calDocs)
.then(_ => {
console.log('Calendar client initialised')
})
})
},
Step 4.
(once) Authorise the gapi client for API calls with
gapi.auth2.authorize(params, callbackFunction)
Important: Scope is a string with spaces! Include email in the scope. Do NOT include the discovery docs here!
params = {
client_id: clientId,
scope: 'https://www.googleapis.com/auth/calendar email',
response_type: 'permission id_token'
}
You can repeat the gapi.auth2.authorize
before any API call with extra params: {prompt: 'none', login_hint: 'emailaddress'}
to refresh the user's access token. This will not show any prompt to the user if he already authorised once for your domain.