I have a Firebase web app,
and want that any user can login and authorize my web app to access his Google Calendars (read/write) on Client AND Server side (to manage calendars when the user is online, and when he's offline).
On Client side.
After creating an API key and a OAuth 2.0 client ID (Web Application) on google developers console,
I've implemented this code:
First, login with Google through Firebase Authentification
firebase.initializeApp({apiKey: 'MY_WEB_APP_API_KEY'})
var provider = new firebase.auth.GoogleAuthProvider()
provider.addScope('https://www.googleapis.com/auth/calendar')
firebase.auth().signInWithPopup(provider)
And, ask authorization that my Web Application can access user's Google Calendar with Google Api JS client
// https://apis.google.com/js/api.js
gapi.load('client:auth2', () => {
gapi.auth2.authorize({
scope: 'https://www.googleapis.com/auth/calendar',
client_id: 'MY_WEB_APPL_CLIENT_ID',
prompt: 'none',
access_type: 'offline',
include_granted_scopes: true
}, () => {
gapi.client.init({
discoveryDocs: ['https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest']
}).then(() => {
return gapi.client.calendar.events.list({
calendarId: 'ANY_USER_CALENDAR_ID' // example: [email protected]
})
}).then((resolve, reject) => {
// IT WORKS ON CLIENT SIDE (RETURNS EVENTS LIST AS EXCEPTED)
})
})
})
Here, everything works as excepted on Client side (read and write to the connected user Google Calendar).
But now, on Server side.
After creating a .json
Service Account Key (App Engine default service account) on google developers console, I've implemented the google-api-nodejs-client on Firebase Cloud Functions, with this code:
const privatekey = require("./MY_WEB_APP_SERVICE_ACCOUNT_KEY.json")
const {google} = require('googleapis')
const jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
['https://www.googleapis.com/auth/calendar']
)
jwtClient.authorize()
const calendar = google.calendar('v3')
calendar.events.list({
auth: jwtClient,
calendarId: 'ANY_USER_CALENDAR_ID' // (in this case, the same previously used on client side: [email protected])
}).then((resolve, reject) => {
// IT DOESNT WORKS ON SERVER SIDE (RETURNS 'Not Found' ERROR...)
})
And here the authentification is working,
but the calendar.events.list()
returns a 'Not Found' error (who's not really helpful...).
If a user previously allowed my web app to access his calendars,
read or write on these calendars through the service account should work?
So I dont understand what I missed or misunderstood? and need explicit code to move forward.
Hoping that my explanation is clear enough.
Thanks for your help!
Step 1: Open your Google calendar from your computer as you can't share it from your Android app. Step 2: From the left panel, under My calendars, hover your cursor near the calendar that you want to share and click on the three dots. Step 3: Choose the Settings and sharing option.
When a user grants permissions to your app (with the Client ID), your app will be able to access the user's information, in this case, Calendar.
However, this is not done through the service account but though the Client ID.
In your sever side code (cloud function), it seems you are using the service account to authenticate to Google Calendar, which means that you are accessing the service account's Calendar and not the Calendar of the user authenticated in the webapp (similar to a regular account, a service account can access services like Drive or Calendar).
Your service account will not have access to the user's Calendar, unless the user gives/shares the Calendar with the service account (similar to sharing the Calendar to other gmail account).
If you want to access that user's Calendar on the server side, you will need to pass the access token and refresh token returned by Google Authentication on the client to your server side. You can then use the access token to make calls to Calendar on behalf of the user.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With