I had the same error/confusion about usage of some of the google apis.
I'm assuming you're using a service account with domain-wide delegation access rights?
Assuming yes, the issue is that in addition to the service account credentials, you need to set a user that the google credentials will impersonate
when making the request. That is, the domain wide delegation only allows you to act as though you are one of the actual users, on my understanding.
I couldn't see any way to set this via google base api, other than using the builder directly. Here is a sample:
static GoogleCredential createCredential(HttpTransport transport, JsonFactory jsonFactory) throws Exception {
final String credentialJsonPath = System.getProperty("user.home") + "/.config/gcloud/service-cred-from-console.json";
try (InputStream credentialStream = new FileInputStream(credentialJsonPath)) {
final GoogleCredential firstPassCred = GoogleCredential.fromStream(credentialStream, transport, jsonFactory);
return new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(firstPassCred.getServiceAccountId())
.setServiceAccountProjectId(firstPassCred.getServiceAccountProjectId())
.setServiceAccountPrivateKey(firstPassCred.getServiceAccountPrivateKey())
.setServiceAccountPrivateKeyId(firstPassCred.getServiceAccountPrivateKeyId())
// service accounts must act on behalf of an actual user and have scope
.setServiceAccountScopes(Lists.newArrayList(GmailScopes.GMAIL_COMPOSE, GmailScopes.GMAIL_SETTINGS_SHARING))
.setServiceAccountUser("a.real.gsuite.account@example.com")
.build();
}
}
The important parts are defining the ServiceAccountUser
(who you impersonate) and the ServiceAccountScope(s)
you are assuming for that user.
I posted an example gmail api gist. You could run this through a local proxy like charles
(et al) if you want the equiv. REST call sequence.