Search code examples
scalagoogle-oauthgoogle-calendar-apigoogle-auth-library-oauth2-http

How do I access the Google Calendar APIs using a service account on behalf of another user? (Using Scala/Java)


I am currently creating an app to help people schedule onto my Google Calendar. To do this I would like to use a Google Service account to access my personal calendar. I have added the service account and given it the Google Calendar permissions. I then add the following code...

  @RequestMapping(path = Array("/"), method = Array(GET))
  def root(): String = {
    val credentials: GoogleCredentials = GoogleCredentials
      .fromStream(new FileInputStream("C:\\...\\me.json"))
      .createScoped(Collections.singleton(CalendarScopes.CALENDAR_READONLY))
    credentials.refreshIfExpired()
    val HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport
    val calendar = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, new HttpCredentialsAdapter(credentials))
      .setApplicationName(appName)
      .build()
    calendar.calendars().get("primary").execute().getSummary
  }

This works but only returns the service account email, I would like a user's info. So I pass my email like this...

    val credentials: GoogleCredentials = GoogleCredentials
      .fromStream(new FileInputStream("C:\\...\\me.json"))
      .createDelegated("me@gmail.com")
      .createScoped(Collections.singleton(CalendarScopes.CALENDAR_READONLY))

But when I run this I get a 401 (presumably because I haven't given Google permissions to share with this SA). How would I tell Google to allow this service account to delegate my user info?

Bonus

  • Would there be a way to allow other users to grant permissions?
  • I am authenticating with Google through Auth0 so would I need to use the management console or something like that?

Solution

  • This was solved similarly to this question

    1. In the calendar settings allow the service access to your account...

    enter image description here

    1. Once added you can access the calendar using the email instead of primary...
      def getCalendarSummary = {
        val credentials: GoogleCredentials = GoogleCredentials
          .fromStream(new FileInputStream(keyLocation))
          .createScoped(Collections.singleton(CalendarScopes.CALENDAR_EVENTS))
        credentials.refreshIfExpired()
        val HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport
        new Calendar.Builder(
          HTTP_TRANSPORT,
          JSON_FACTORY,
          new HttpCredentialsAdapter(credentials)
        )
          .setApplicationName(appName)
          .build()
          .calendars()
          .get("person@gmail.com")
          .execute()
          .getSummary
      }
    

    The service account can now add and remove events