0

I'm trying to get my Groovy/Grails application to speak to the Google Calendar API from Java, using a service model. For now I'll be happy with a simple calendar list. No matter what I do though, I end up with:

URI: /test
Class: com.google.api.client.auth.oauth2.TokenResponseException
Message: 400 Bad Request { "error" : "invalid_grant" }

The same user "googleaccounts@quirk.biz" owns both the calendar and the API Console App. Code as follows:

package quirkplanner

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport
import com.google.api.client.http.HttpTransport
import com.google.api.client.json.JsonFactory
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.calendar.Calendar
import com.google.api.services.calendar.model.*;

class TestController {

    def servletContext

    private static final HttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
    private static final JsonFactory JSON_FACTORY = new JacksonFactory();

    private static final String SERVICE_EMAIL = "12345678901234-abcdefabcdef@developer.gserviceaccount.com";
    private static final String CLIENT_ID = "12345678901234.apps.googleusercontent.com";
    private static final String PATH_TO_CERTIFICATE = "/WEB-INF/abcdefabcdef-privatekey.p12";
    private static final String SERVICE_ACCOUNT_USER="my-google-admin-user@quirk.biz";

    def index() {

        GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
            .setJsonFactory(JSON_FACTORY)
            .setServiceAccountId(SERVICE_EMAIL)
            .setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/calendar"))
            .setServiceAccountPrivateKeyFromP12File(new File(servletContext.getRealPath(PATH_TO_CERTIFICATE)))
            .setServiceAccountUser(SERVICE_ACCOUNT_USER)
            .build();

        Calendar service3 = new Calendar(HTTP_TRANSPORT, JSON_FACTORY, credential);
        com.google.api.services.calendar.model.Calendar calendar = service3.calendars().get("primary").execute();

        render("ok")
    }
}

BuildConfig.groovy Dependencies are:

    compile 'com.google.api-client:google-api-client:1.18.0-rc'
    compile 'com.google.http-client:google-http-client-jackson2:1.18.0-rc'

And I also have a list of JAR's I'm using. The list it not complete, hence the BuildConfig dependencies. Ideally, I should really choose one or the other...

Image of the Grails lib folder

halfer
  • 18,701
  • 13
  • 79
  • 158
sparkyspider
  • 11,590
  • 8
  • 73
  • 113
  • Any particular reason for **not** using [OAuth plugin](http://grails.org/plugin/oauth) or [Google for Spring Security OAuth plugin](http://grails.org/plugin/spring-security-oauth-google)? – dmahapatro Apr 08 '14 at 13:42
  • On a first glance I see two issues: 1. don't know where `httpTransport` is coming from, should it be `HTTP_TRANSPORT`. 2. You don't need `def servletContext` it is available in controller artefact. – dmahapatro Apr 08 '14 at 15:07
  • @dmahapatro No reason. Just following Google documentation. httpTransport casing was a typo. Apologies. – sparkyspider Apr 08 '14 at 15:34
  • Can you also add the dependencies what you have used in `BuildConfig.groovy`? – dmahapatro Apr 08 '14 at 15:41
  • @dmahapatro added dependencies. – sparkyspider Apr 08 '14 at 16:04
  • There are two different versions of `google-api-client` used. One from `lib` (which is not at all a good idea to start with) and the other from `BuildConfig`. I suggest you take some time and go through those two plugins I mentioned earlier. Also here is a [sample app](https://github.com/bagage/grails-google-authentification-example) using google spring security oauth plugin which would help as well. – dmahapatro Apr 08 '14 at 16:26
  • As you got `invalid_grant` error, have a look at this question: http://stackoverflow.com/questions/10025698/authentication-on-google-oauth2-keeps-returning-invalid-grant?lq=1 – andyf Apr 11 '14 at 05:19

2 Answers2

1

There are a few things that could try:

  1. Drop and re-create your private keys in the Google Console.
  2. Share one of the calendars from within the Google Calendar of the service account owner (googleaccounts@quirk.biz) with the SERVICE_EMAIL address.
  3. Do not try to impersonate an account. Remove setServiceAccountUser(SERVICE_ACCOUNT_USER)

Be sure to use the SERVICE_EMAIL for the

.setServiceAccountId(SERVICE_EMAIL)

as you have correctly done. Google's documentation is not clear on this but using the Service Account ID will not work.

Good Luck!

Glen
  • 534
  • 2
  • 3