0

I used Service Account key with scope (https://www.googleapis.com/auth/admin.directory.user.readonly) to access Google Directory API Users.

With the same setup as below, I can access Users List API (link).

But when trying to make request to Users Watch API (link), Status 403 returned.

These 2 APIs required the same scope user.readonly that my SA key has.

My domain has already been verified and added into Domain verification screen on GCP Console.

val httpTransport = GoogleNetHttpTransport.newTrustedTransport()
val jsonFactory = JacksonFactory()
val inputStream = HealthController::class.java.getResourceAsStream("/credentials.json")
        ?: throw FileNotFoundException("/credentials.json")
val credential = GoogleCredential.fromStream(inputStream, httpTransport, jsonFactory)
        .toBuilder()
        .setServiceAccountScopes(listOf(DirectoryScopes.ADMIN_DIRECTORY_USER_READONLY))
        .setServiceAccountUser("admin@example.com")
        .build()
service = Directory.Builder(httpTransport, jsonFactory, credential)
        .setApplicationName("Some Name")
        .build()

val channel = Channel()
channel.address = "https://example.com/webhook/v1/google/users"
channel.expiration = Instant.now().toEpochMilli() + 6 * 60 * 60 * 1000
channel.id = "webhook001"
channel.token = "abcxyz"
channel.type = "web_hook"
channel.payload = false

val result = service.users().watch(channel)
        .setDomain("example.com")
        .setViewType("domain_public")
        .execute()

I logged the issue to Google issue tracker: https://issuetracker.google.com/issues/171300784

NDC00629
  • 33
  • 4
  • Have you tried with `https://www.googleapis.com/auth/admin.directory.user` scope in your token? – Jose Vasquez Oct 21 '20 at 09:19
  • @JoseVasquez No I haven't, should I try it? – NDC00629 Oct 21 '20 at 11:02
  • Which JVM version is your Kotlin compiling for execution? This might be affecting your code since Google doesn't directly support Kotlin for **Directory API**, take a look to your version and confirm this is one of the following [here](https://github.com/googleapis/google-api-java-client#ci-status). – Jose Vasquez Oct 27 '20 at 09:35
  • I used kotlin-maven-plugin with jvmTarget to be 1.8 – NDC00629 Oct 28 '20 at 11:48
  • but JVM version on my local machine is 11 – NDC00629 Oct 28 '20 at 11:49
  • After further investigation, reproducing your code, using your same JVM target version and JVM on my environment I can use the **watch** method. This 403 error might be produced because the the version of your google packages which can be **Deprecated**. Can you please adapt your code an try with [ServiceAccountCredentials](https://googleapis.dev/java/google-auth-library/latest/com/google/auth/oauth2/ServiceAccountCredentials.html) instead of [GoogleCredentials](https://googleapis.dev/java/google-auth-library/latest/com/google/auth/oauth2/GoogleCredentials.html) and make sure that you adapt... – Jose Vasquez Oct 30 '20 at 15:09
  • your credentials `HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(googleCredentials);` by using the [HttpRequestInitializer](https://googleapis.dev/java/google-http-client/latest/com/google/api/client/http/HttpRequestInitializer.html) Interface and [HttpCredentialsAdapter](https://googleapis.dev/java/google-auth-library/latest/index.html?com/google/auth/http/HttpCredentialsAdapter.html) Class. Otherwise please confirm which versions you are using in your google dependencies. – Jose Vasquez Oct 30 '20 at 15:11
  • @JoseVasquez: thanks for a great insight, I'll give it a try. I don't even know about class ServiceAccountCredentials, I know about class GoogleCredentials from Google Admin SDK documentation site example. And yes, with latest version of Google API oauth package, this class is deprecated. – NDC00629 Oct 31 '20 at 08:07

1 Answers1

1

Google Directory API doesn't support Kotlin directly it depends on the target compilation

Prerequisites

Make sure that you have Delegating domain-wide authority to the service account activated.

Workaround

As an approach in JAVA (you can transpile this code to Kotlin if needed) first of all use the watch method of the official documentation as well as the Channel class, I'll put the package dependency in a comment:

JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

// com.google.auth.oauth2.ServiceAccountCredentials
GoogleCredentials credentials = ServiceAccountCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_CREDENTIALS_FILE_PATH))
            .createScoped(SCOPES)
            .createDelegated("impersonated@example.com");

// com.google.api.client.http
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);

// com.google.api.services.admin.directory.Directory.Builder
Directory service = new Directory.Builder(httpTransport, jsonFactory, requestInitializer)
                .setApplicationName(APPLICATION_NAME)
                .build();

// com.google.api.services.admin.directory.model.Channel
Channel channel = new Channel();
channel.setAddress("https://example.com/webhook/v1/google/users");
channel.setExpiration(Instant.now().toEpochMilli() + 6 * 60 * 60 * 1000);
channel.setId("webhook001");
channel.setToken("abcxyz");
channel.setType("web_hook");
channel.setPayload(false);

System.out.println(service.users().watch(channel)
                .setDomain("example.com")
                .setViewType("domain_public")
                .execute());

Reference

Javadoc Directory API

Jose Vasquez
  • 1,678
  • 1
  • 6
  • 14