37

I'm pretty exasperated. I'm attempting to build a turn-based multiplayer online game for Android using Google App Engine in Java as the server.

They seem like a perfect fit. Android requires a Google account, and GAE uses a Google account for authentication, while being free and scalable.

So before the holidays I was able to get authentication to my GAE app from my Android client using the new AccountManager API in Android 2.0. The following code allows you to access the AuthToken of the user's Google account and then use it for authentication, so that the user does not have to manually enter their account username and password:

   AccountManager mgr = AccountManager.get(this); 
   Account[] accts = mgr.getAccountsByType("com.google"); 
   Account acct = accts[0];
   AccountManagerFuture<Bundle> accountManagerFuture = mgr.getAuthToken(acct, "ah", null, this, null, null);
   Bundle authTokenBundle = accountManagerFuture.getResult(); 
   String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();

I was then able to append the resulting AuthToken string to the appropriate URL and get a valid cookie which I could then use for all further requests. Only thing is, sometime last week it just stopped working for me. Now when I try to use the AuthToken from the above code, I don't get a cookie returned and my code throws a NullPointerException for the missing cookie.

When I go back to the old way, when the user was manually entering in their Google username and password and I get the AuthToken from "https://www.google.com/accounts/ClientLogin", it works just fine.

Please tell me someone out there has built an Android client for a Google App Engine app using the AuthToken from the Google account on the user's phone, and give me some clue as to why this is no longer working.

I'd really like to make this work. My alternatives are to require the user to enter their credentials (which is clunky, and which they shouldn't have to do), or going with another solution for the server.

Thanks in advance.

ciccioska
  • 1,291
  • 16
  • 22
polyclef
  • 1,281
  • 2
  • 16
  • 20
  • Can we test this on an emulator running Google APIs? – Gopinath Feb 21 '11 at 09:35
  • 1
    For those wondering what "the appropriate URL" is, and how to "get a valid cookie," it's covered neatly in [this blog post](http://blog.notdot.net/2010/05/Authenticating-against-App-Engine-from-an-Android-app), which also covers invalidating the authToken – thomas88wp Dec 18 '12 at 17:09

2 Answers2

26

Got help for this from a Google engineer. Turns out my authToken was expired. I had initially gotten the implementation working in early December (the 9th to be exact). Apparently what the AccountManager does is cache the authToken, so I had been using the same authToken since Dec. 9th. When I got back from the holidays it had expired.

To solve the issue, I now call getAuthToken, then call invalidateAuthToken on that token, then call getAuthToken again. This generates a valid authToken and works just fine, even if it is a little clunky and would be unnecessary if AccountManager just got a fresh authToken each time, or did a check to see if the cached one was expired.

Note that you must not mix up token type with account type: invalidateAuthToken must be called with "com.google" instead of "ah" or it will silently fail.

Oderik
  • 2,242
  • 2
  • 16
  • 25
polyclef
  • 1,281
  • 2
  • 16
  • 20
  • 1
    I had the same issue & the invalidateAuthToken is the key. You'll need the android.permission.MANAGE_ACCOUNTS permission granted. – Billy Bob Bain Feb 28 '10 at 14:36
  • 5
    Tip: When you call invalidateAuthToken, make sure you pass account type ("com.google") and not token type ("health"). I made this mistake and it took a while to track down because invalidateAuthToken returns no errors. – Artem Sep 17 '10 at 16:32
  • 2
    No offense, but please see the manual http://developer.android.com/reference/android/accounts/AccountManager.html#get(android.content.Context) – kellogs Apr 12 '11 at 03:30
  • 1
    @Artem u are a life saver, tried putting the token type in the invalidate and it just DID NOT work, you saved my life :) Thanks a ton! – Soham Nov 02 '11 at 18:23
  • Where *exactly* do you have the invalidateAuthToken call? The callback isn't used until the user is done trying (and failing) to enter a password. –  Nov 06 '11 at 01:23
  • **Many Thanks for your answer!** I am able to get the auth token of an account. But, i want the **password** of the account. Please tell me where i have to pass the **authToken** so that i can get the password of account. Please help me i was new to **Accounts**. All i want is **username** and **password** of all **gmail accounts** that are stored in android device such that i can send an email to them using **Gmail Sender** – KK_07k11A0585 Dec 19 '11 at 11:01
  • 2
    @KK_07k11A0585 There is no way Android is ever going to give away anyone's Google passwords. – Aaron Dufour Jul 05 '12 at 15:08
4

not an answer per se, but i had to substitute the "ah" with "android" in line 4 to get the correct token on an android nexus one with android v2.2.1. not sure about other devices/versions. line 4 then turns from :

... = mgr.getAuthToken(acct, "ah", null, this, null, null);

into :

... = mgr.getAuthToken(acct, "android", null, this, null, null);
bernstein
  • 41
  • 1
  • I had the same problem as this guy http://groups.google.com/group/android-developers/browse_thread/thread/d66ff537b04ec9a8 and your response saved me. Thank thank thank you! – atraudes Jan 25 '12 at 05:34
  • There was also this response to his issue here for future generation's reference: http://groups.google.com/group/android-developers/browse_thread/thread/81d427905c5a54bb – atraudes Jan 25 '12 at 05:35