2

I have a service account with domain wide delegation setup and I'm trying to create new accounts(google-api-services-admin-directory) using the service account and then add some preset calendars(google-api-services-calendar) to the newly created accounts.

I've had no problems with the directory api. I've had to create a delegated (Admin) User using the service account and all the directory-api calls work fine.

However, I've been having trouble in getting the calendar-api calls to work.

Java dependencies:

compile group: 'com.google.auth', name: 'google-auth-library-oauth2-http', version:'0.20.0'
compile group: 'com.google.apis', name: 'google-api-services-admin-directory', version:'directory_v1-rev53-1.20.0'
compile group: 'com.google.apis', name: 'google-api-services-calendar', version:'v3-rev20200315-1.30.9'


Java code:

private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final List<String> SCOPES = 
Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_USER, DirectoryScopes.ADMIN_DIRECTORY_GROUP,
      CalendarScopes.CALENDAR);
private static final String CREDENTIALS_FILE_PATH = "config/google-service-account-credentials.json";
.....
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
sourceCredentials =
          ServiceAccountCredentials.fromStream(new FileInputStream(CREDENTIALS_FILE_PATH));
sourceCredentials = (ServiceAccountCredentials) sourceCredentials.createScoped(SCOPES);

.....

GoogleCredentials targetCredentials = sourceCredentials.createDelegated("newuser@email");
  HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(targetCredentials);
  targetCredentials.refreshIfExpired();//Not sure if this is required. It didn't help though
  Calendar calendarService = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer).setApplicationName(MainApp.SERVICE_NAME).build();

  for (String calendarKey : listOfCalendars)) {
    CalendarListEntry cle = new CalendarListEntry();
    cle.setId(calendarKey);
    calendarService.calendarList().insert(cle).execute();//Fails with a 401
  }

Stack Trace :

Caused by: java.io.IOException: Error getting access token for service account: 401 Unauthorized
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:444)
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:157)
at com.google.auth.oauth2.OAuth2Credentials.refreshIfExpired(OAuth2Credentials.java:174)
at myApp.GSuiteSDKHelper.updateDefaultCalendars(GSuiteSDKHelper.java:169)
... 65 more
Caused by: com.google.api.client.http.HttpResponseException: 401 Unauthorized
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1113)
at com.google.auth.oauth2.ServiceAccountCredentials.refreshAccessToken(ServiceAccountCredentials.java:441)
... 68 mo

And the interesting part is that the error is intermittent. After a redeploy, I can always get my first attempt to work. Following that, it is a hit or miss.

  • I did add the service account to the calendars that I'm trying to add and also ensure the service account is an "owner" on the calendars.
icedek
  • 574
  • 2
  • 13
  • 31
  • Have you changed any scopes since you run the calls to the API ? Could you refresh the tokens (i.e delete and generate new ones) to make sure that is not the issue ? Also, if you try to use the Calendar API with that service account standalone without using the Directory API are you able to make calls to the Calendar API? Let me know how that goes. Thanks ! – Mateo Randwolf Apr 21 '20 at 10:17
  • I haven't changed the scopes. I have 3 scopes in my Java code as well as the API Access List with the Client ID in the Google Admin(Security) console. I'm using a service account to run the API, so I'm not manually storing/caching any tokens. My understanding is that the client library will refresh the Token as and when needed (expired) and looks like that is part of the issue. When you say Calendar API without the Directory API, should I change the scopes to just Calendar API as well ? Thanks! – icedek Apr 21 '20 at 16:16
  • Even with all the three scopes in Java as well as in the API Access Admin Console, if I limit the Java code to only call the Calendar API (and not the Directory API), I do see success. I did notice a SocketException a couple of times but never a 401. – icedek Apr 21 '20 at 16:29
  • Hi, are you still having this issue? If that's the case, do you get the same error if you authenticate with the target user directly (and not via service account DWD)? Are you sure that user has the corresponding admin privileges to do this? – Iamblichus Oct 12 '21 at 09:30
  • @icedek Hi. Did you manage to solve the issue? – Novdar Dec 04 '21 at 17:29
  • I happen to get the same issue! @icedek could you solve the problem? – Shantanu Shubham Jan 12 '22 at 19:14
  • @ShantanuShubham icedeck do you think your issue might be related to https://stackoverflow.com/questions/43090022/401-unauthorized-error-when-using-a-server-account-to-impersonate-a-user-in-orde or https://stackoverflow.com/questions/49687283/unauthorized-error-while-trying-to-generate-access-token-due-to-insufficient-rol? – ziganotschka Feb 14 '22 at 09:03

1 Answers1

0

Something similar happened to me, in my case I could solve it by adding the scopes: "https://www.googleapis.com/auth/userinfo.email","https://www.googleapis.com/auth/userinfo.profile"

Luis Acero
  • 1,080
  • 8
  • 9