MesamH
MesamH

Reputation: 101

TokenResponseException: 401 Unauthorized Exception when trying to access Admin SDK Google API.

I am trying to do an extract of users in my domain by accessing the Google Admin SDK API. I am however given a 401 unauthorized exception. The code below is my settings class that contains my method to call the API.

 package com.brookfieldres.operations;

   import java.io.File;
   import java.io.IOException;
   import java.security.GeneralSecurityException;
   import java.util.ArrayList;
   import java.util.ResourceBundle;

   import org.apache.log4j.Logger;

   import com.brookfieldres.common.Constants;
   import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
   import com.google.api.client.googleapis.auth.oauth2.GoogleCredential.Builder;
   import com.google.api.services.admin.directory.Directory;
   import com.google.api.services.admin.directory.DirectoryScopes;

    public class GCAuthentication {

        private static final Logger _Log =      Logger.getLogger(GCAuthentication.class.getName()); 

    static ResourceBundle resources =  ResourceBundle.getBundle("Resources"); 

//  public static String serviceAcc = resources.getString("SERVICE_ACC_EMAIL"); 
//  public static String privKeyPath = resources.getString("PRIVATE_KEY_PATH"); 
//  public static String userEmail = resources.getString("ADMIN_ACC"); 



    public static Directory getDirectoryService(String serviceAcc, String privKeyPath, String userEmail) throws IOException, GeneralSecurityException, NullPointerException {

    //  final ArrayList<String> dirScopes = new ArrayList<String>(); 
    //      dirScopes.add(DirectoryScopes.ADMIN_DIRECTORY_USER); 


        Constants.dirScopes = new ArrayList<String>(); 
        Constants.dirScopes.add(DirectoryScopes.ADMIN_DIRECTORY_USER); 
        Constants.dirScopes.add(DirectoryScopes.ADMIN_DIRECTORY_CUSTOMER); 
        Constants.dirScopes.add(DirectoryScopes.ADMIN_DIRECTORY_ORGUNIT);

        GoogleCredential gCreds = new GoogleCredential.Builder()
        .setJsonFactory(Constants.JSON_FACTORY)
        .setTransport(Constants.HTTP_TRANSPORT)
        .setServiceAccountId(serviceAcc)
        .setServiceAccountUser(userEmail)
        .setServiceAccountPrivateKeyFromP12File(new File(privKeyPath))
        .setServiceAccountScopes(Constants.dirScopes)
        .build(); 

        Directory directory = new Directory.Builder(Constants.HTTP_TRANSPORT, Constants.JSON_FACTORY, gCreds).setApplicationName(Constants.APPLICATION_NAME).build(); 

        return directory; 

    }


}

The code below is my test case that i am using to pull users from my domain:

package com.brookfieldres.library.test;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertFalse;

import java.io.IOException;
import java.security.GeneralSecurityException;
import org.junit.After;

import com.brookfieldres.operations.GCAuthentication;
import com.google.api.client.repackaged.com.google.common.base.Strings;
import com.google.api.services.admin.directory.Directory;
import com.google.api.services.admin.directory.model.Customer;
import com.google.api.services.admin.directory.model.User;

public class ExtractionTest { 

@Before 
    public void setUp(){}

@Test
    public void getEmails() throws IOException, NullPointerException, GeneralSecurityException{ 

        try {

            Directory directory = GCAuthentication.getDirectoryService("XXXXXXX", "XXXXXXXX", "XXXXXXX"); 
            System.out.println("The connection to Google is established"); 
            User user1 = directory.users().get("[email protected]").execute(); 
            System.out.println("User is pulled."); 

    //      assertFalse(user1 == null); 

    //      if(user1 != null){ 
    //          System.out.println("Name= " + user1.getName());
    //      }

        }catch(NullPointerException e) { 
            e.printStackTrace();
        }catch (IOException e){ 
            e.printStackTrace();
        }catch (GeneralSecurityException e) { 
            e.printStackTrace();
        }


    }

@After
    public void tearDown(){ }

}

and Finally here is the exception that i am faced with.

The connection to Google is established
com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized
    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:384)
    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:868)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
    at com.brookfieldres.library.test.ExtractionTest.getEmails(ExtractionTest.java:36)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Any help would be gladly appreciated!!!

Upvotes: 3

Views: 16697

Answers (4)

Mathew Sullivan
Mathew Sullivan

Reputation: 36

I was running into this same issue when trying to use the Admin SDK Google API with a service account.

The issue was occurring for me because the Scopes that were set in my code did not match those set at my Google Admin Console under "Security > Advanced Settings > Manage API client access". Once these were aligned it all started working perfectly.

You also are required to have Domain Wide Delegation on for your service account? (This can be done here)

Upvotes: 2

Prashant Abdare
Prashant Abdare

Reputation: 2475

In my case in Intellij IDE, it cashed the credential file which was the issue. So if you are changing the google account and credential file you must also delete the cashed credentials. It is located in your project directory under token/StoredCredential

TokenResponseException: 401 Unauthorized Exception when trying to access Admin SDK Google API.

Upvotes: 6

Pankaj Kumar Katiyar
Pankaj Kumar Katiyar

Reputation: 1494

try deleting .credential directory - which is created in your local machine. this works.

Upvotes: 0

abielita
abielita

Reputation: 13469

Based from this thread, TokenResponseException: 401 Unauthorized occurs when having an invalid client ID, client secret or scopes. But it could also be due to refresh token overuse. Refresh the access token, if necessary since it have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.

Check these related threads:

Hope this helps!

Upvotes: 3

Related Questions