12

I'm trying to authenticate a mobile application for the Android platform to a custom node.js server api. I would like to use Google OAuth2 tokens for this rather than roll my own authentication, since Android devices with Google Play installed make this available to app developers. I'm using the GoogleAuthUtil.getToken call from the Google Play Services library, documented here. I'm trying to follow the advice outlinedin this android developers blogpost

The getToken method is returning in my case a long 857 byte string. If I try to pass this token to Google's TokenInfo endpoint, it returns:

{'error': 'invalid_token', 'error_description': 'Invalid Value'}

What am I doing wrong here? In the 'scope' of the getToken call, I am sending: audience:server:client_id:**i_put_my_clientid_here**. I have a clientid generated for "installed applications". Using this client id, the call to getToken doesn't work at all. When I generated a client id for a "service account", the call succeeds, but I get an 857 byte token that fails when passed to the TokenInfo endpoint as described above.

EDIT: I also created a client id for "web applications", as it appears that is the right client id to use when calling getToken. But the behavior is the same, I get back an 857 byte token that doesn't validate when calling Google's endpoint.

How can I properly get a valid auth token using Google Play services on Android? Once I have the right token, what is the right node.js library to validate it server side? Can I use passport-google-oauth ?

Anton I. Sipos
  • 3,493
  • 3
  • 27
  • 26

5 Answers5

4

Hm, this is really a comment rather than an answer, but I can’t put newlines in those:

  1. it has to be the web-side Clent ID that goes in the put_my_clientid_here spot
  2. if GoogleAuthUtil.getToken() gives you a String withou throwing an Exception, it really ought to be valid. When you hit tokeninfo, did you use ...tokeninfo?id_token=<857-byte-value-here>
  3. if you’re a rubyist, grab the google-id-token gem and see if it can validate your 857-byte token.
Tim Bray
  • 1,653
  • 11
  • 16
  • Yes! id_token worked. I was using access_token before. Where can I find some good reading explaining the difference? Now I just need to find the proper way to verify these in a Node.js server, without calling google's endpoint everytime. Will ping Jared more for that. Thanks! – Anton I. Sipos May 01 '13 at 21:39
  • With the google-id-token gem, presumably the 'audience' parameter gets the web-side client-id. But what goes into the required_client_id parameter? I tried with my "installed applications" id, but it didn't work - regardless, the installed applications client id wasn't used in the generation of the id_token using getToken. – Anton I. Sipos May 02 '13 at 00:34
3

If you just want to read the contents of the data returned by GoogleAuthUtil.getToken then the process is very simple. The returned data is simply a JWT. So all you'd have to do is split the data by the . character, and then base64 (url) decode each piece.

It gets slightly more complicated if you want you want to verify the message's authenticity. Simply use your favorite crypto library to do the verification. The 3rd component of the JWT is the signature of the data and the Google certs are publicly available; that's all you need to verify the message.

George
  • 449
  • 3
  • 10
  • I have extracted the three parts and need to verify the id_token. Are the SHA256(header + "." + payload) equal to the decrypted signature? Or is the decrypted signature equal only to the hash of the payload? Is it equal pre or post the data gets Base64 encoded? My function for veryfying the token with the google certs is not working, so I'm just wondering. Thanks – kingSlayer Aug 11 '14 at 17:10
  • the signature is for sha256(header+"."+payload) – George Aug 12 '14 at 19:30
2

For a week I have been looking into how to validate GoogleAuthUtil tokens received in Android Client application at Node.js server using passport.js

Finally I came across passport-google-token passport strategy which perfectly performs the task.

https://www.npmjs.com/package/passport-google-token

More details are present in the above link.

  • Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Yurii Mar 27 '15 at 07:12
2

The official node SDK lets you do that now.

Here's the link: https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/oauth2client.js#L384

Krzysztof Kozmic
  • 27,267
  • 12
  • 73
  • 115
1

I'm not too familiar with the details of how Android works with respect to handing a token from the device to the server. My general impression, however, is that you don't go through the typical web-based OAuth dance. Instead, you directly call the "user info" endpoint, which will return the info corresponding to the user who holds the token, or reject the request if the token is invalid. There's some discussion on this related question:

validating Android's authToken on third party server

In effect, the token becomes a secret that is shared between both the device and your server, so its important to protect it.

There are a couple strategies for Facebook and Twitter that were developed to do similar things using tokens from iOS devices:

https://github.com/drudge/passport-twitter-token
https://github.com/drudge/passport-facebook-token

You can take some inspiration from them and tweak it to talk to Google's endpoints. Let me know how this turns out. I'd love to see a similar "passport-google-token" strategy, so if you implement one, let me know and I'll link to it!

Community
  • 1
  • 1
Jared Hanson
  • 15,940
  • 5
  • 48
  • 45
  • I'm more or less trying to follow the flow outlined here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html . On an Android device, you have already authenticated yourself to a Google account. The Google Play Services implementation uses this fact to bypass some of the other workflow steps. I'm able to get an auth token from Google, and in theory Google allows me to verify this without a server call. But the token I get back is so far being considered invalid. It also seems too long (857 bytes). – Anton I. Sipos May 01 '13 at 20:48
  • If Google's response is a JWT, and the certs google uses to make these are available at https://www.googleapis.com/oauth2/v1/certs , can I just use https://github.com/xtuple/passport-oauth2-jwt-bearer to validate these tokens without calling google on my server side? – Anton I. Sipos May 01 '13 at 23:17
  • I believe the oauth2-jwt-bearer is used for the case where you are implementing an OAuth 2.0 server. I'd take a look at the following: https://github.com/mozilla/jwcrypto https://github.com/brianloveswords/node-jwa https://github.com/brianloveswords/node-jws – Jared Hanson May 02 '13 at 00:38