Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Access Google Calendar REST API v3 with Java

I'm working on a project where I have to access a set of Google Calendars using REST and working with Java.

The program, situated on a private non-Google server, periodically (via cron job) connects to the Google account, gets the list of Calendars linked to the account, gets the last month's events of each calendar, and returns an XML file containing all the information. The program should be able to execute and access calendars WITHOUT any user input. For the moment, the project specifies that the Calendar will just be read, not modified (so only GET/LIST calls will be made).

I have looked through the Google documentation and been over the sample codes using client libraries, and almost all examples given require OAuth 2.0 user consent before accessing calendar API. Even the REST API documentation pages require you activate OAuth 2.0 to return requested information (otherwise returning a HTTP 40X error code and JSON file containing error status and message).

How could I connect to the Google Calendar REST API to get the information I need, everything being done via REST calls, and without requiring user consent at the time of execution?

Or am I over-complicating things, and only require the 'Server Key', found in the Resgistered Apps part of the Google Cloud Console?
Or am I requiring to use both OAuth and developer key? (I found someone mention it here under a question with the title : Google Calendar API v3 hardcoded credentials ; however, the question and solution were for PHP, and I don't know if something similar would be possible or necessary in Java).

  • I did see the possibility of creating a JWT with a service account (with Google cloud console, register as a Web Application, and it's under 'certificate'), but I did not find how I would use this in conjunction with a REST call from a Java program.
  • The following link (http://aleksz-programming.blogspot.be/2012/11/google-calendar-api.html) says that it is possible to access information via 'Web server applications' or 'Installed applications', but doesn't go into detail. However, on the Google OAuth 2.0 documentation page, the 'Web server applications' part still requires user input & consent. Which is true?
  • I also found this page (https://developers.google.com/accounts/docs/OAuth2Login), but failed to see how it could be used without using a user consent page.
  • I did see some references to a '2-legged OAuth'. But it seems that this is not a OAuth 2.0, but a version 1 was of doing things. Is it a possible solution for my project? If so, what information would I need from Google Cloud Console to get it working?

I hope I have given enough information as to what I'm looking for, and also that this question hasn't been covered so far. I did research it, and didn't find anything close enough to what I was looking for.

I was unable to post more than 2 links (lacking reputation), but did look at the Google Calendar v3 REST API, as well as the page specifying the creation of a JWT.

like image 836
AntonH Avatar asked Nov 19 '13 16:11

AntonH


2 Answers

If you just need to access a particular set of calendars, I would create a service account and share the necessary calendars with that account.

To do so:

  1. Create a "Service Account" in this Cloud Console (it is found under "Web application" / "Certificate").
  2. Download the private key and store in a safe place.
  3. Take note of the email address associated with the service account.
  4. Share (via Calendar user interface) any necessary calendars with this email address.
  5. Install Google API Java Client libraries (https://developers.google.com/api-client-library/java/apis/).

Then you should be able to use the following code:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.json.gson.GsonFactory;
import java.io.File;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import java.util.Arrays;
import com.google.api.services.calendar.Calendar;

GoogleCredential credentials = new GoogleCredential.Builder().setTransport(GoogleNetHttpTransport.newTrustedTransport())
  .setJsonFactory(new GsonFactory())
  .setServiceAccountId("<service account email address>@developer.gserviceaccount.com")
  .setServiceAccountScopes(Arrays.asList("https://www.googleapis.com/auth/calendar.readonly"))
  .setServiceAccountPrivateKeyFromP12File(new File("<private key for service account in P12 format>-privatekey.p12"))
.build();
Calendar client = new Calendar.Builder(GoogleNetHttpTransport.newTrustedTransport(), new GsonFactory(), credentials).build();
client.<do calendar stuff>.execute();

If instead you are a domain administrator who needs to access calendars for all Google Apps accounts that are part of your domain without consent from individual users, then instead of step 4 above:

  1. Take note of the client ID associated with the service account. This can be found in the client_secrets.json file - typically in the form 1234.apps.googleusercontent.com.
  2. Authorize this client to make requests on behalf of users in your organization. See https://support.google.com/a/answer/162106?hl=en for steps - use whichever scopes you will be requesting later.

You should now be able to write code like the following:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.json.gson.GsonFactory;
import java.io.File;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import java.util.Arrays;
import com.google.api.services.calendar.Calendar;

GoogleCredential credentials = new GoogleCredential.Builder().setTransport(GoogleNetHttpTransport.newTrustedTransport())
  .setJsonFactory(new GsonFactory())
  .setServiceAccountId("<service account email address>@developer.gserviceaccount.com")
  .setServiceAccountScopes(Arrays.asList("https://www.googleapis.com/auth/calendar"))
  .setServiceAccountPrivateKeyFromP12File(new File("<private key for service account in P12 format>-privatekey.p12"))
  .setServiceAccountUser("<domain user whose data you need>@yourdomain.com")
.build();
Calendar client = new Calendar.Builder(GoogleNetHttpTransport.newTrustedTransport(), new GsonFactory(), credentials).build();
client.<do calendar stuff as that user>()
like image 196
aeijdenberg Avatar answered Oct 14 '22 21:10

aeijdenberg


In addition to the steps mentioned in @aeijdenberg's answer, the Service Account now needs to explicitly accept the shared calendar by adding it to its CalendarList via CalendarList.insert. See:

Service Accounts don't accept automatically shared calendars anymore [148804709] https://issuetracker.google.com/issues/148804709

like image 23
Bernard Desruisseaux Avatar answered Oct 14 '22 20:10

Bernard Desruisseaux