Search code examples
javaspring-bootgoogle-calendar-apiservice-accountsgoogle-api-java-client

Error getting access token for service account: 401 Unauthorized\nPOST https://oauth2.googleapis.com/token; Google Calendar API


I have integrated Google Calendar with business email of my company. Everything works fine if we use email with our own domain. However, if a certain user uses with a simple gmail.com domain the error pops up that states: "Error getting access token for service account: 401 Unauthorized".

I am a newbie in Google Calendar API. Is it possible to use Calendar with business domain and a simple domain emails?

Here are my credentials:

{
  "type": "service_account",
  "project_id": "example",
  "private_key_id": "***",
  "private_key": "****",
  "client_email": "example.gserviceaccount.com",
  "client_id": "***",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/*****-service-account%40dms-web-281206.iam.gserviceaccount.com"
}

My code:

   static private GoogleCredentials getCredentials(String email) {
        try {
            ClassPathResource res = new ClassPathResource("credentials.json");
            InputStream inputStream = res.getInputStream();

            GoogleCredentials credentials = ServiceAccountCredentials.fromStream(inputStream).createScoped(SCOPES)
                    .createDelegated(email);
            return credentials;
        } catch (Exception e) {
            throw new ApiException(HttpStatus.INTERNAL_SERVER_ERROR.value(), ErrorCodes.GOOGLE_CLIENT_ERROR(),
                    "Google Credentials error: " + e.getMessage());
        }
    }

    private Calendar getClient(String email) {
        try {
            final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(getCredentials(email));

            return new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
                    .setApplicationName("dms-web-281206")
                    .build();
        } catch (Exception e) {
            throw new ApiException(HttpStatus.INTERNAL_SERVER_ERROR.value(), ErrorCodes.GOOGLE_CALENDAR_ERROR(),
                    "Google calendar error: " + e.getMessage());
        }
    }

Solution

  • You are using a service account. Service accounts get their authorization though the domain wide delegation set up in Google workspace.

    Domain wide delegation will only work on accounts within the domain. A standard gmail user account is not on your domain there for your service account can not access it.

    You can read more about in the delegatingauthority documentation page.

    Of note.

    Your application now has the authority to make API calls as users in your domain (to "impersonate" users).

    So to be clear service accounts with google calendar do not work on standard gmail users. It only works with workspace domain accounts. After domain wide delegation has been configured, and then only for users on that domain.