8

I am using the followin code to get an Access Token, after connecting to Google+, to get profile info and e-mail:

String sAccessToken = GoogleAuthUtil.getToken(this,mPlusClient.getAccountName() + "",
                          "oauth2:" + Scopes.PLUS_PROFILE + " 
                          https://www.googleapis.com/auth/userinfo.profile 
                          https://www.googleapis.com/auth/userinfo.email");

This Access Token I am not storing and trying to re-use. Instead I ask for an Access Token everytime, expecting a new(different) Token, so that I don't need to check whether its expired etc..

But I am getting the same Access Token every time I ask for. I uninstalled the app, cleared data of Google+ App and still I get the same Access Token.

The Actual problem is, using this Access Token gives a 401 error - "message": "Invalid Credentials"

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "authError",
    "message": "Invalid Credentials",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Invalid Credentials"
 }
}

This is a response on browser.

On a device I get this in Logcat:

02-25 02:09:46.919: W/System.err(3022): java.io.FileNotFoundException: https://www.googleapis.com/oauth2/v1/userinfo
02-25 02:09:46.929: W/System.err(3022):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:521)
02-25 02:09:46.929: W/System.err(3022):     at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:258)
02-25 02:09:46.929: W/System.err(3022):     at com.example.gmaillogin.MainActivity$connectAsyncTask.doInBackground(MainActivity.java:269)
02-25 02:09:46.929: W/System.err(3022):     at com.example.gmaillogin.MainActivity$connectAsyncTask.doInBackground(MainActivity.java:1)
02-25 02:09:46.929: W/System.err(3022):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
02-25 02:09:46.929: W/System.err(3022):     at java.lang.Thread.run(Thread.java:1019)

Line 269:

urlConnection = (HttpURLConnection) url.openConnection();

Complete Code:

URL url = new URL("https://www.googleapis.com/oauth2/v1/userinfo");
String sAccessToken = GoogleAuthUtil.getToken(
                        MainActivity.this,
                        mPlusClient.getAccountName() + "",
                        "oauth2:" + Scopes.PLUS_PROFILE + " 
                                            https://www.googleapis.com/auth/userinfo.profile 
                                            https://www.googleapis.com/auth/userinfo.email");

            Log.d("sAccessToken = ", "" + sAccessToken);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("Authorization", "Bearer "
                    + sAccessToken);

            BufferedReader r = new BufferedReader(new InputStreamReader(
                    urlConnection.getInputStream(), "UTF-8"));
            StringBuilder total = new StringBuilder();
            String line;
            while ((line = r.readLine()) != null) {
                total.append(line);
            }
            line = total.toString();

EDIT:

This is definitely because the Access Token is expired. Which was expected, but I thought I will get a new Access Token everytime I call.

But as said here:

If the android device already has an auth token (for the particular GData service you're trying to access), it will be returned to you

So, I have to do this:

if (server indicates token is invalid) {
              // invalidate the token that we found is bad so that GoogleAuthUtil won't
              // return it next time (it may have cached it)
              GoogleAuthUtil.invalidateToken(Context, String)(context, token);
              // consider retrying getAndUseTokenBlocking() once more
              return;
          }

like the docs say

But how can I check if the Access Token is expired or invalid?

By catching the Exception - Is the only solution?

Actually the Exception is java.io.FileNotFoundException which doesn't make sense.

Community
  • 1
  • 1
Archie.bpgc
  • 23,812
  • 38
  • 150
  • 226
  • Is there a reason that you're trying to do this manually rather than use the provided methods on the PlusClient? The client should handle the token exchanges on your app's behalf automatically. – BrettJ Mar 06 '13 at 17:00
  • I followed [this](https://developers.google.com/+/mobile/android/people#retrieve_an_authenticated_users_email_address) to get the Access token. What is the other way where its automatically handled? – Archie.bpgc Mar 06 '13 at 17:33

2 Answers2

4

Covering the bases here: Did you register a Google APIs Console project and create a OAuth 2.0 client ID for your Android app, by specifying your app's package name and the SHA-1 fingerprint of your certificate (test or prod)?

Often the 401 invalid credentials message is due to the APIs Console project either not being configured or one of the settings being invalid.

The steps to walk through that set up process specifically for the Google+ SDK are here: https://developers.google.com/+/mobile/android/getting-started

Edit

The PlusClient can automatically handle your tokens for you. I'd suggest using the methods that the PlusClient provides and allowing the client to manage the tokens rather than doing it manually. If you need email or profile data via the PlusClient see PlusClient.loadPerson() and for email PlusClient.getAccountName(), more details at https://developers.google.com/+/mobile/android/people

BrettJ
  • 6,801
  • 1
  • 23
  • 26
  • 1
    Yeah, I did what all you mentioned in the answer. After some research I found out its definitely because of the `Access Token`. **Is there a way to check whether an Access Token is expired or valid?** – Archie.bpgc Mar 06 '13 at 04:54
  • See the quickstart samples for some code on how to verify/validate tokens so they are not only valid but also valid for this given user and app. The Java server-side app verification can be seen starting on line 140: https://github.com/googleplus/gplus-quickstart-java/blob/master/src/com/google/plus/samples/quickstart/Signin.java#L141 – BrettJ Mar 06 '13 at 17:01
  • Hey @BrettJ, this used to work for me, but only a few days ago it stopped working and now it throws this error com.google.android.gms.auth.GoogleAuthException: Unknown. Any idea why? Is there something wrong with my scopes? https://gist.github.com/lawloretienne/7351151 – Etienne Lawlor Nov 07 '13 at 17:09
  • Did you recently upgrade your SDK and Google Play Services? – BrettJ Nov 07 '13 at 18:01
0

I had the similar problem. To solve the issue with Access Token expiration, I decode the token on client-side, and check "exp" field in token payload. In that way, I can recognize token expiration before sending to server. More details are on this blog post

bsvtag
  • 318
  • 1
  • 7