Google Directory API returns Not Authorized when call users().list().execute()

13,231

Solution 1

I had the exact same problem, and was stucked on this sample

What helped me : 1/ I did not Delegate domain-wide authority to your service account, as suggested by Jay Lee. But after that, I still had the problem. 2/ Then, according to this post, the call to setServiceAccountUser([email protected]) is mandatory.

Solution 2

you can go to "security" settings in the admin console (admin.google.com/AdminHome?chromeless=1&pli=1#SecuritySettings:); then click on advance settings > Manage third party OAuth Client access. After this map your client id(generated from appconsole code.google.com/apis/console under API access for oath2) and "One or More API Scopes". Use comma separated scopes as mentioned there. For google directory you can use https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.user

Hope after this it works :)

Solution 3

Google Directory API works with Compute Engine default service account, you do not need to setup Google Drive domain-wide. The only thing: you have to set serviceAccountUser, which is not supported in JSON based credentials. So you can

  • use P12 keys
  • user JSON credentials with workaround:

make credential copy:

import static com.google.api.client.googleapis.util.Utils.getDefaultJsonFactory;
import static com.google.api.client.googleapis.util.Utils.getDefaultTransport;

private static final String APPLICATION_NAME = "AnyAppName";

private final List<String> SCOPES = ImmutableList.of(
        DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER, DirectoryScopes.ADMIN_DIRECTORY_USER, DirectoryScopes.ADMIN_DIRECTORY_GROUP);

private Directory service;

@PostConstruct
void init() throws GeneralSecurityException, IOException {
    GoogleCredential credential;
    try (InputStream is = new FileInputStream("./config/client_secret.json")) {
        credential = GoogleCredential.fromStream(is);
    }
    GoogleCredential credentialWithUser = new GoogleCredential.Builder()
            .setTransport(getDefaultTransport())
            .setJsonFactory(getDefaultJsonFactory())
            .setServiceAccountUser("[email protected]")  // <--- mail of domain's admin
            .setServiceAccountId(credential.getServiceAccountId())
            .setServiceAccountScopes(SCOPES)
            .setServiceAccountPrivateKey(credential.getServiceAccountPrivateKey())
            .setServiceAccountPrivateKeyId(credential.getServiceAccountPrivateKeyId())
            .setTokenServerEncodedUrl(credential.getTokenServerEncodedUrl()).build();

    service = new Directory.Builder(getDefaultTransport(), getDefaultJsonFactory(), credentialWithUser).setApplicationName(APPLICATION_NAME).build();
}

 public void members() throws IOException {
    Members members = service.members().list("[email protected]").execute();
    System.out.println(members);
 }

For my trial G Suite account it works!

Solution 4

You can grant the service account access to certain scopes in the Control Panel as explained in the Google Drive domain-wide documentation. Just use Admin SDK scopes instead.

The application name is used in the User-Agent header of requests and so is not overly important, just use your apps name and maybe version.

Share:
13,231

Related videos on Youtube

dmitry747
Author by

dmitry747

Updated on June 04, 2022

Comments

  • dmitry747
    dmitry747 almost 2 years

    I need to read the list of users (and groups) from my google domain.

    So I went to my Google APIs Console and enabled Admin SDK and created a Service Account to call Google APIs. I use the following google libraries

    • google-api-services-admin-directory_v1-rev11-1.16.0-rc.jar
    • google-api-client-1.16.0-rc.jar

    My code is

         /*
         * Global instance of the JSON factory.
         */
        final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
         /*
          Global instance of the HTTP transport.
         */
            HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    
            Collection<String> scopeList = new ArrayList<>();
            scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_USER);
            scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_GROUP);
            scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER);
    
            GoogleCredential credential = new GoogleCredential.Builder()
                    .setTransport(httpTransport)
                    .setJsonFactory(JSON_FACTORY)
                    .setServiceAccountId("[email protected]")
                    .setServiceAccountScopes(scopeList)
                    .setServiceAccountPrivateKeyFromP12File(new File("/Path/To/KeyFile/nnnnn-privatekey.p12"))
    //                .setServiceAccountUser("[email protected]")
                    .build();
    
            Directory admin = new Directory.Builder(httpTransport, JSON_FACTORY, credential)
                    .setApplicationName("Test")
                    .setHttpRequestInitializer(credential).build();
    
    
            Users users = admin.users().list().setDomain("mydomain.org").execute();
    

    And I receive this on the last line

    Error

    {
      "code" : 403,
      "errors" : [ {
        "domain" : "global",
        "message" : "Not Authorized to access this resource/api",
        "reason" : "forbidden"
      } ],
      "message" : "Not Authorized to access this resource/api"
    }
        at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
        at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
        at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
        at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1045)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
    

    If I uncomment the commented line (.setServiceAccountUser("[email protected]")) then I get a different error

        Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
    {
      "error" : "access_denied"
    }
        at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
        at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
        at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
        at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
        at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
        at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
        at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:858)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
    

    My account ([email protected]) is a super administrator. I suspect the Service Account needs to be granted access for the users API scope. But I can not find where I can grant this access. I have a classic UI mode of my Google CPanel. And I don't have "Manage client API access" page in the Advanced tools.

    Advanced tools

    Also I'm not sure what I should use as an Application Name at .setApplicationName("Test").

    Thanks for any help

  • dmitry747
    dmitry747 over 10 years
    Thanks for your response. I can not find this "Manage third party OAuth Client access." item in the Advanced tools in my Control Panel as described in the Google Drive doc. Probably I need to enable it somehow?
  • Jay Lee
    Jay Lee over 10 years
    See instructions at: support.google.com/a/bin/answer.py?hl=en&answer=162106. It sounds like you may have the new admin console enabled.
  • dmitry747
    dmitry747 over 10 years
    I couldn't find this "Manage client API access" page. I added a picture of my Advanced tools. Probably I need to enable something?
  • Jay Lee
    Jay Lee over 10 years
    What edition of Google Apps are you using? (EDU, Business, Free/Standard)?
  • dmitry747
    dmitry747 over 10 years
    I'm using Google Apps Partner Edition
  • Jay Lee
    Jay Lee over 10 years
    According to: developers.google.com/admin-sdk/directory/v1/guides/… under "Setup the basics", GAfP is not a supported edtion. You could try accessing the API directly as a super admin using standard OAuth 2.0 but I do not believe Service Accounts are an option for you.
  • dmitry747
    dmitry747 over 10 years
    I moved to the old gdata API. That API seems doing what I need to.
  • dmitry747
    dmitry747 over 10 years
    Thanks for all your help
  • dmitry747
    dmitry747 over 10 years
    I've got the classic admin console. The pages are on other locations.
  • heyyan khan
    heyyan khan over 9 years
    i am using a trial account and not getting this option, just says 'Manage OAuth Client access'. is it because of the trial or is there some configuration required