1

I have generated my client library from my endpoints, and also passed the appropriate credential (the client ID is 100% correct) for my authenticated call to the endpoints.

But I am still getting this error when I run my codes:

com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException
            at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:286)
            at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
            at com.projects.malaysiakini.Home$ContentApi.doInBackground(Home.java:165)
            at com.projects.malaysiakini.Home$ContentApi.doInBackground(Home.java:141)
            at android.os.AsyncTask$2.call(AsyncTask.java:288)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)
     Caused by: com.google.android.gms.auth.GoogleAuthException: Unknown
            at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
            at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
            at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential.getToken(GoogleAccountCredential.java:255)
            at com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential$RequestHandler.intercept(GoogleAccountCredential.java:279)
            at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
            at com.projects.malaysiakini.Home$ContentApi.doInBackground(Home.java:165)
            at com.projects.malaysiakini.Home$ContentApi.doInBackground(Home.java:141)
            at android.os.AsyncTask$2.call(AsyncTask.java:288)
            at java.util.concurrent.FutureTask.run(FutureTask.java:237)
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
            at java.lang.Thread.run(Thread.java:841)

This is my code below:

 private class ContentApi extends AsyncTask<Void,Void,String>{

       @Override
       protected String doInBackground(Void... params) {
           String response = null;


           try {
               settings = getActivity().getSharedPreferences("MApi", Context.MODE_PRIVATE);
               credential = GoogleAccountCredential.usingAudience(getActivity(), CLIENT_ID);
               setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

               Core.Builder builder = new Core.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), credential);
               builder.setApplicationName(getActivity().getPackageName());

               service = builder.build();



               if (credential.getSelectedAccountName() != null) {
                   // Already signed in, begin app!

                response = service.info().execute().getLang();
               }//end if
               else {
                   chooseAccount();
               }

               }//end try
               catch(IOException ex){
                   Log.d("MkiniCore", ex.getMessage(), ex);
               }//end catch



           return response;
       }//end doInBackground

       @Override
       protected void onPostExecute(String s) {
          textView.setText(s);
       }
   }

I just edited the code to answers below but am still getting this errors

This is the code for the Account picker:

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            case REQUEST_ACCOUNT_PICKER:
                if (data != null && data.getExtras() != null) {
                    String accountName =
                            data.getExtras().getString(
                                    AccountManager.KEY_ACCOUNT_NAME);
                    if (accountName != null) {
                        setSelectedAccountName(accountName);
                        SharedPreferences.Editor editor = settings.edit();
                        editor.putString(PREF_ACCOUNT_NAME, accountName);
                        editor.commit();
                        // User is authorized.
                    }
                }
                break;
        }
    }

this is the setSelectedAccountName method

private void setSelectedAccountName(String accountName){
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(PREF_ACCOUNT_NAME, accountName);
        editor.commit();
        credential.setSelectedAccountName(accountName);
        this.accountName = accountName;
    }//end setSelectedAccountName
Isaac
  • 296
  • 1
  • 4
  • 14

1 Answers1

3

You need to set the application package name in the builder before calling .build():

builder.setApplicationName(getActivity().getPackageName());

Also, if this is an authenticated call, you will have had to run the user through the account picker to select a Google account and also set that in the credentials:

String accountName = ...;  //  Pull from where ever you are storing it
credential.setSelectedAccountName(accountName);

Also, it's not obvious from the provided code what CLIENT_ID is for the audience (scope), so make sure it is in the format:

static final String CLIENT_ID = "server:client_id:" + YOUR_WEB_APP_CLIENT_ID;

Since you are using cloud endpoint's generated library, you do not have to set the root URL or use the raw HTTP request/response. The endpoint generated library is already doing the HTTP request prep and HTTP response JSON parsing for you. Without seeing your cloud API, I'm guessing here that your cloud method for "category" returns something modeled as Category which has a member field detail which can be retrieved with the getter getDetail():

builder.setApplicationName(getActivity().getPackageName());
credential.setSelectedAccountName(accountName);
service = builder.build();
Core.Info.Category endpoint = service.info().category("en");
String category = endpoint.execute().getDetail();
Larry Schiefer
  • 15,687
  • 2
  • 27
  • 33
  • I just did that.. and it is still giving me the same error – Isaac Apr 09 '15 at 17:52
  • OK, I realized there were a couple of other things in which to watch for, see the edits I just made to the answer. – Larry Schiefer Apr 09 '15 at 18:04
  • I have adjusted the code accordingly but am not getting another error.. check my question.. I edited my questions to accordingly – Isaac Apr 09 '15 at 18:55
  • Did you run the user through the AccountManager's "picker" functionality to allow them to select a Google account to authorize? If you have not done that then GMS will throw an exception with "Unknown" like shown in your updated log. – Larry Schiefer Apr 09 '15 at 19:08
  • I just added some lines of code to my edit question... is that what you are referring to?.. by the way, is this call correctly made: HttpResponse response = service.info().sections("en").buildHttpRequest().execute(); – Isaac Apr 09 '15 at 19:27
  • OK, the account picker stuff appears to be OK, though I cannot tell if you are reading/writing to the same `SharedPreference`. As far as the HTTP request goes, you don't have to do that if you are using cloud endpoints and using the generated libs. Once you call the builder's `build()` method, you can get the endpoint API and call it - this will automatically handle the HTTP transaction for you. The API to call will depend on your cloud API definition. – Larry Schiefer Apr 09 '15 at 20:06
  • okay... so if the account picker appears to be ok then what is the problem... i just added the setSelectedAccountName method to my edited quesion..... can we please chat on hangout to communicate faster please.... because i reeaallly need your help on solving this now – Isaac Apr 09 '15 at 20:14
  • It could be because you're manually calling the HTTP request's execute or setting the URL, neither should be required. The endpoint will marshall all of the JSON data for you. I'll update the answer above shortly. – Larry Schiefer Apr 09 '15 at 20:27
  • trust me... its still not working... still giving the same errors... the error has been pointing the service object line of code (service.info().category("en")).. – Isaac Apr 09 '15 at 21:02
  • yes... i did.. like this: Core.Info.Category endpoint = service.info().category("en"); response = endpoint.execute().getLanguage(); – Isaac Apr 09 '15 at 21:43
  • Right, but it is because GMS is flagging a problem. It still looks like an account auth issue. – Larry Schiefer Apr 10 '15 at 02:21
  • okay.. could it be that because the SHA1 fingerprint I submitted while creating my Client ID was in this format:5b:c0:70:05:40:0c:00:1a:1e:8c:b6:bc:66:93:d2:4f:1b:7c:47:55 OR because when I generated that SHA1 fingerprint, I was still compiling my android studio application with JDK 8 because am now using JDK 7.... These are the only things I could think of that might have been causing the problem.. – Isaac Apr 12 '15 at 19:10
  • Hmm, probably not. If the client ID didn't match you would see a 403 error rather than an exception like this. This looks more like the selected Google account being used for authentication wasn't properly selected via `AccountManager` or doesn't exist on the device accounts. – Larry Schiefer Apr 12 '15 at 19:41
  • I figured what happened.... I have been passing my android client id as my web app client id since..... but I have been doing that because I can't find the web client id (I only have one id given to me) when i created the client id... and what am i supposed to do with the android client id and how can I find the web app client id? – Isaac Apr 14 '15 at 01:25
  • You create the web client ID and use it as the audience for the request. You do this in the Google developer console for your app, just like you did for the android client ID (but select web client instead.) The android client will be used based on the package name and signing key. So when you set the package name in the credentials it also picks up the signing key info. – Larry Schiefer Apr 14 '15 at 01:46
  • Not sure why you'd be seeing this. Something doesn't make sense. Did you try running through the "HelloEndpoints" example for Android and verify you could get that working? – Larry Schiefer Apr 14 '15 at 19:39
  • :-) Hopefully that'll help shed some light on things for you. I know the first time I ran through it I hit a similar problem as you are seeing and it's because I was setting the "account name" in the credentials object without first going through the AccountManager to select the account. So AccountManager (really, the Google account authentication manager) hadn't be approved/allowed the account to be used by my app. Once I hooked it up it started working just fine. – Larry Schiefer Apr 14 '15 at 19:45
  • 1
    I just tried it out with my HelloEndpoint and still gave the same error.. Then I found out that it was the SHA1 fingerprint that was wrong... so I changed it to the correct one. and it received a token finally..... so I want to try it now on the real deal..... – Isaac Apr 15 '15 at 05:34
  • so I can finally connect to the endpoint but am getting 403 forbidden error... I checked my app engine log and its showing this: `Audience not allowed: 901326459160-vnpoik6ebefbnhtagqns7r0qlkt31gdo.apps.googleusercontent.com` – Isaac Apr 16 '15 at 05:10
  • Getting close! Double check that with your web app I'd. Also, the audience string set in the Google credential object has a prefix on it: `server:client_id:` (I mentioned this in my answer). – Larry Schiefer Apr 16 '15 at 12:50
  • This is the [link](http://stackoverflow.com/questions/29667442/google-cloud-endpoint-authentication-from-my-android-client-audience-not-allowe) to the detailed error am receiving.. – Isaac Apr 17 '15 at 00:07
  • The web client email was passed as the audience instead of the web client id in the endpoint Api method.... I can now get the content... – Isaac Apr 17 '15 at 05:46
  • Interesting, not the same as what I use. – Larry Schiefer Apr 17 '15 at 21:42
  • I meant.. the error was coming because the web Client email was passed as the audience instead of the web client ID.. – Isaac Apr 20 '15 at 02:01
  • 1
    Thank you very much. adding builder.setApplicationName(getActivity().getPackageName()); and changing my client id to web from android, here static final String CLIENT_ID = "server:client_id:" + YOUR_WEB_APP_CLIENT_ID; worked for me. can you explain why its working with web client id than android. it suppose to work with the android right? – Irfan Oct 29 '15 at 13:18
  • Unfortunately, no. Google's docs simply state that for Android you have to use the web app client ID: https://cloud.google.com/appengine/docs/python/endpoints/getstarted/clients/android/add_auth_code – Larry Schiefer Oct 29 '15 at 13:37