We build an app for a client of ours, who is a medical practioner. She wants her patients to use the app to book appointments and these would then appear on her Google calendar.
I wrote this article because our team found it a little difficult to navigate Google documentation and find the way to achieve this.
Admitedly our use case is not the usual OAuth2 flow.
In the usual OAuth2 flow, the app would prompt the Google calendar owner to give consent to the app to access the owner’s calendar. But in our case, we want the app to programmatically access the client’s Google calendar. In other words, we want the app to impersonate the Google calendar owner.
OAuth2 for Service Accounts / Server to Server Application
After numerous re-reads of Google OAuth2 documentation, I finally realised that the OAuth2 for Service Accounts is the relevant authentication method for us.
The Google OAuth 2.0 system supports server-to-server interactions such as those between a web application and a Google service. For this scenario you need a service account, which is an account that belongs to your application instead of to an individual end user. Your application calls Google APIs on behalf of the service account, so users aren't directly involved. This scenario is sometimes called “two-legged OAuth,” or “2LO.” (The related term “three-legged OAuth” refers to scenarios in which your application calls Google APIs on behalf of end users, and in which user consent is sometimes required.)
I found the term service account is a still bit vague, you can read more about it in Understanding Service Accounts
A service account is a special type of Google account that belongs to your application or a virtual machine (VM), instead of to an individual end user. Your application assumes the identity of the service account to call Google APIs, so that the users aren't directly involved. A service account can have zero or more pairs of service account keys, which are used to authenticate to Google.
So firstly we need to create a service account, this is the easy part, you can just follow the documentation above to do that.
Note that by the end of step 3, you will have a credential file downloaded to your computer, take note of the location of this file as you will need it to call Google API.
Ignore the domain-wide authority
Much of our confusion stems from the repeated emphasis on Google documentation for G Suite domain.
This is not relevant of our case, as we do not use Google do host our domain.
This is the area where I think Google documentation is lacking, that is how to grant access to the service account when you do not have G Suite domain.
Granting Service Account access to Google Calendar
As mentioned above, Google documentation doesn't mention this, so this bit took the longest to work out.
It turns out to be quite simple, basically all we need to do is share the calendar with the service account.
To do this, firstly note the email / service account identifier that you created before, it probably looks like this:
Then access the Google calendar that you want to grant access to by going to Google Calendar.
Click the Gear and choose settings:
Then choose the 2nd tab “Calendars”.
Click Shared: Edit Settings link next to your calendar.
Then lastly add the service account email address in the enter email address input, choose a permission setting that is appropriate, for our purpose that will be Make changes to event.
Calling the Google Calendar API
I am using Ruby as an example here, following the Using OAuth2 for Server to Server Applications (Ruby)
You'd need googleauth gem and google-api-client gem.
You can gem install them by issuing the following:
gem install googleauth gem install google-api-ruby-client
Or better still if you are using bundler, here is the Gemfile version:
# A sample Gemfile source "https://rubygems.org" gem 'googleauth' gem 'google-api-client'
Here is the sample code to list calendars that the service account has access to.
Note on the credential file on line 5, that’s the credential file that you've downloaded on the creating service account step above.
require 'googleauth' require 'google/apis/calendar_v3' scopes = ["https://www.googleapis.com/auth/calendar"] credential_file = File.open('path-to-my-service-account-credentials.json') authorizer = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: credential_file, scope: scopes) calendar = Google::Apis::CalendarV3::CalendarService.new calendar.authorization = authorizer # List of calendars that the service account has access to calendar_lists = calendar.list_calendar_lists # Example of adding an event to a calender calendar_id = calendar_lists.items.first.id # calendar.quick_add_event(calendar_id, 'Test event', send_notifications: true)
If all is well, you will see the event added to the intended calendar.
Hope that helps!