Android: Google SSO - OAuth or AccountManager? Or both? - android

After reading all sorts of Stackoverflow postings and various documentation including some on http://code.google.com/p/google-api-java-client/ site I feel utterly confused. So can someone explain to me the best way of achieving the following:
Let user to approve my app. I don't really care if this is done by accessing their registered Google account in accounts/settings and approving the app (preferred way) or by calling Google OAuth authentication page
Obtain the authentication token that can be used to communicate with Google Reader
Another point of confusion for me - I was able to approve my app using AccountManager and get auth token from it but it won't work with Google Reader. So how to balance Account information from the AccountManager and OAuth? Do I still need to do anything with OAuth after I get approved by user in AccountManager settings?
Code example would be nice but I look more for some clear explanation on how all these pieces are related to each other

The account manager lets you get authentication tokens for different services. There are different concrete implementation under the hood: ClientLogin, OAuth, etc. To get it to work with, say, Google Reader, you need to pass the appropriate token type. For ClientLogin, those are short string like "ah" (App Engine) and "reader" (Google Reader). For OAuth, they are scopes, as defined by each service. So, what are you passing as the authTokenType parameter?
Getting the token is asynchronous, since it may involve network access. If there is a cached token, it will be returned right away, if valid. The flow is not that complicated, see the link above for the pretty picture. Once you get the token, you put it in the appropriate header, and use the API as per the spec.

Here's an Android training class on AccountManager that might help:
http://developer.android.com/training/id-auth/authenticate.html
Also, using AccountManager with Google Reader is currently the only preferred way of doing this. Directing your users to a login page with a WebView is not very secure and using a browser isn't supported by Google APIs as far as I know (I'm also not sure if Reader uses OAuth2 or not).

Related

Using Android AccountManager for 3rd party OAuth2 authorization

I am working on an app that will need to get authorization via OAuth2 from a 3rd party web service (3rd party meaning it's not Google and I don't own it).
This article:
http://developer.android.com/training/id-auth/authenticate.html
seems to suggest that I should be using AccountManager for this purpose. After giving this some thought, I have some doubts about the benefit of doing this, or even if it's appropriate for me to do this. If I wanted to use a Google account, or some other account that was already installed into AccountManager by some other app, then obviously it would be a good idea to get the credentials from AccountManager. But since I am going to use an account that is most likely not in AccountManager, I would have to do all the work to get it installed.
Does AccountManager provide any support in actually handling OAuth2 requests? If it doesn't, then what do I gain by using it?
And since I don't own the web service associated with this account type, is it even appropriate for me to be installing such accounts into AccountManager?
Thank you!
This might be a rather late answer after all these 4 years, but let me give you a short reply.
You cannot and should not be installing third-party accounts for Oauth yourself. It is the job of those third-party OAuth providers such as Facebook or Twitter to implement AccountManager functionality and create their own account type. This is roughly guided at https://developer.android.com/training/id-auth/custom_auth.html.
There are several services, including OAuth providers such as Facebook, Twitter, WeChat, and etc, who register user accounts in AccountManager but I believe most of them just use it to implement SyncAdapter (which requires Account), not to provide OAuth functionality to third-party applications like your app.
I think Google allows you to use their APIs using the token acquired through AccountManager; the link you provide gives an example of using AccountManager for Tasks API. However, using the client library is a better option of achieving the same thing as described in https://developers.google.com/google-apps/tasks/quickstart/java#step_3_configure_the_project_build.
If the third-party OAuth provider does not provide you any SDKs or client libraries, you have no other choice but to use REST APIs they provide.

What are values for authTokenType in the Android AccountManager getAuthToken?

The Facebook application for Android provides an authenticator for the AccountManager.
I'm trying to get the access token with the method getAuthToken, but I do not know what are the possible values for the parameter authTokenType.
What values are available for this parameter?
Thanks.
It shouldn't be possible for you to get an access token via Facebook's Authenticator, as this would constitute a fairly significant security hole.
Instead you should use the single-sign-on api described here: https://developers.facebook.com/docs/mobile/android/build/#enablesso
The instructions there for getting started are really good.
If you really really wanted the authTokenType value facebook uses, you could probably get it by rooting your phone and reading it out of the authentication database. I don't think this will let you read any access tokens however, and this is definitely not advised for legitimate business purposes.
Just for information, decompiling the Facebook application APK shows that the server part of the getAuthToken method is not implemented.
You need to use the Facebook SDK.

Authenticating with OAuth2 for an app *and* a website

I'm developing a website that is primarily accessed via an app, and I want to use OAuth2 for user registration and authentication. Since it is an Android app I will start using Google's OAuth2 stuff, since it provides a decent UI on Android.
Google states that "You can choose to use Google's authentication system as a way to outsource user authentication for your application. This can remove the need to create, maintain, and secure a username and password store." which is what I want to do. However when I go through all their examples and whatnot, I can only find stuff about having a website or an app authenticate a user against Google's services.
And indeed, when I go to register my app ("client") with Google's OAuth2 there are options for website clients and "installed" clients (i.e. a mobile app) but not both. I can create two separate clients but I read the OAuth2 draft and I think there will be a problem, which I will now explain.
Here's how I did envisage it working:
User asks MyApp to access his private data.
App uses Android's AccountManager class to request an access token for Google's APIs.
Android says to user "The app 'MyApp' wants access to your Basic Information on Google. Is this ok?"
User says yes.
AccountManager connects to Google's OAuth2 server using the credentials stored on the phone, and asks for an access token.
Access token (which follows the green lines) is returned.
AccountManager returns the access token to MyApp.
MyApp sends a request to MySite for the user's private data, including the access token.
MySite needs to verify the user, using the access token. It validates the token as described here, with Google - "Google, is this token valid?".
Now, what I want to happen is that Google says "Yes, whoever gave it to you is indeed that user.", but what I think will actually happen (based on the OAuth2 draft and Google's documentation) is that it will say "No way! That token is only valid for MyApp, and you're MySite. GTFO!".
So how should I do this? And PLEASE don't say "Use OpenID" or "Don't use OAuth2" or other similarly unhelpful answers. Oh and I would really like to keep using the nice AccountManager UI rather than crappy popup WebViews
Edit
Provisional answer (I will report back if it works!) from Nikolay is that it should actually work, and Google's servers won't care where the access token came from. Seems a bit insecure to me, but I will see if it works!
Update
I implemented this pattern with Facebook instead of Google and it totally works. The OAuth2 server doesn't care where the access token comes from. At least Facebook's doesn't, so I assume Google's doesn't either.
In light of that it is a very very bad idea to store access tokens! But we also don't want to have to hit Facebook/Google's servers to check authentication for every request since it will slow everything down. Probably the best thing is to add an additional authentication cookie for your site that you hand out when their access token is validated, but a simpler way is just to treat the access token like a password and store a hash of it. You don't need to salt it either since access tokens are really really long. So the steps above become something like:
9. MySite needs to verify the user, using the access token. First it checks its cache of hashed valid access tokens. If the hash of the token is found there it knows the user is authenticated. Otherwise it checks with Google as described here, with Google - "Google, is this token valid?".
10. If Google says the access token is invalid, we tell the user to GTFO. Otherwise Google says "Yes that is a valid user" and we then check our registered user database. If that Google username (or Facebook id if using Facebook) is not found we can create a new user. Then we cache the hashed value of the access token.
I just posted an answer to a similar StackOverflow question.
Google calls this Hybrid Apps and explains how an "Android app obtains offline access for Web back-end".
The gist of it is that you'll have to pass a massaged scope string into GoogleAuthUtil.getToken in order to get it to return an Authorization Code (not an OAuth2 Token). That Authorization Code can be passed from your mobile app to your server and be exchanged for an OAuth2 Token and Refresh Token, according to this schematic.
The scope parameter needs to look something like this:
oauth2:server:client_id:<your_server_client_it>:api_scope:<scope_url_1> <scope_url_2> ...
You can use the access token retrieved by the mobile application anywhere else. Drive SDK has a nice and simple intro that goes through the flow on https://developers.google.com/drive/quickstart-android
it describes exactly what you want:
https://developers.google.com/identity/protocols/CrossClientAuth
You probably need OpenID Connect, which uses OAuth tokens for authentication. As for AccountManager, the current OAuth support is a bit hacky, the new Google Play Services, set to be released 'soon' should hopefully make this better. See here for a demo.
At least with Google, the access token eventually expires. This is why the android AccountManager has the invalidateAuthToken method--the cached access token has expired, and you need to tell the AccountManager to stop giving you the old one and instead get a new one. This makes it somewhat safer to cache the token, as the token itself doesn't give you eternal access as that user. Instead, when valid, it merely says "at some point in the recent past, this token was acquired by a trusted source."
Here are a couple of things I've found helpful when working with tokens. The first is Google's tokeninfo endpoint. The token itself is just base64-encoded JSON. This means it isn't encrypted, so you need to be sure to be using HTTPS for communication. However, it also means that you can examine the token and have a better idea of what's going on.
https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=
If your token was "abcdef", you would navigate to:
https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=abcdef
and Google would unpack the token for you. It is a simple JSON object that includes an "expires_in" field telling you the number of seconds for which the token is still valid. At 6:03 in the video below you can see the unpacked token:
https://developers.google.com/events/io/sessions/383266187
That video includes a thorough overview of OAuth2 and is well worth watching in its entirety if you're going to be dealing with OAuth and tokens. The speaker also discusses other forms of Oauth2 tokens, that are not access tokens, that do not expire.
Another useful resource is the OAuth Playground. This lets you do basic things like request scopes, make up requests, and get back tokens. This link seems to work sporadically, and on Chrome I had to install the Oauth Playground app:
https://developers.google.com/oauthplayground/
And here is a tutorial by Tim Bray, the speaker in the video, explaining how to use access tokens to communicate to a server from an Android app. This was useful to me because I began to understand how the different things in the Google API Console work together:
http://android-developers.blogspot.in/2013/01/verifying-back-end-calls-from-android.html
With regards to the actual answer to your question, I would say you never need to cache the access token on the server. As explained in the Verifying Back End Calls from Android link above, verifying a token is almost always a fast static call, meaning there's no reason to cache the tokens:
The libraries can cache the Google certs and only refresh them when required, so the verification is (almost always) a fast static call.
Finally, you can indeed use the AccountManager to get access tokens. However, Google now instead encourages the use of the GoogleAuthUtil class in the Play Services library instead:
In a nutshell what's the difference from using OAuth2 request getAuthToken and getToken
Here note the comment by Tim Bray, the same guy yet again from the above links, saying that they are putting their efforts into the GoogleAuthUtil route. Note, however, that this means you would be limited to Google authentication. I believe that the AccountManager could be used to get, for example, a Facebook token instead--not the case with GoogleAuthUtil.
When we had a need to do something similar on a non-google OAuth Server, we kept the tokens in a DB on the website. The app would then use web services to request the token when needed to request data.
The user could do the OAuth registration on either the web or app. They shared the same application token, so they could share the same access token. After the registration we would store the access and refresh tokens in the DB for use from whichever app needed it.

Get Google AuthSub token from android app

I'm writing an android program which must interact with google documents, so I have watched this sample, but it uses an AuthSub token. How can I get an AuthSub Token from an android app?
For accessing Google Docs or any other Google service (or any OAuth based service for that matter) you will need to find a way to do an OAuth based authentication, after which you can u get a secure token which you can use to access a service based on the users credentials.
There are some really good examples to get you started:
This is an example of getting AccountManager to work with a Google
service like Google Tasks, this shows you how to generate tokens and
then how to use them:
https://developers.google.com/google-apps/tasks/oauth-and-tasks-on-android
This is an in-depth look into how you can authenticate based on the
users Android credentials, has an example of how things work and how
the UI should be:
http://www.finalconcept.com.au/article/view/android-account-manager-step-by-step-2
For something specific to Google Docs have a look at
http://code.google.com/p/google-api-java-client/wiki/Android
http://code.google.com/p/gdata-java-client/source/browse/trunk/java/sample/docs/DocumentResumableUploadDemo.java

Android APP that consumes a webservice how to authenticate users

I'm developing an android app that consumes a webservice that I will develop too (I'm thinking in using a RESTFul webservice)..
and I want to secure the connection between the app and the server but I need to authenticate users too..
My problem is in the last part, to secure the connection I think the best way to do it is to use SSL (https), am I wrong?
I don't know what's "the best way" to authenticate users, to make sure that a user cannot consume the webservice as another user..
I have some ideas, like using a authenticate(login,pass) method on the webservice that returns a token.. And for any operation that requires authentication the user would need to pass that token as a parameter.. The thing is, is this a good way to do this? whats the most common technique used to auth users in a situation like this?
If a token based auth is a good idea how should I generate the token?
Sorry for this long text..
Any help will be usefull
Thanks
Make sure you understand a trendy standard like OAuth before you go down that path. Most OAuth flows are centered around a user logging in to your server through a web browser. This can lead to pretty bad user experience for a mobile app. The standard does allow for alternatives. Here's a decent introduction.
You could also use an existing identity provider like Google, Facebook, Twitter, etc. instead of implementing your own authN/authZ. On Android, you can ask for a Google auth token using the AccountManager. This usually works because the user needs to be logged in to their Google account to access the Android Market. Anyway, this will prompt the user to grant authorization to your app. You could then use the Google auth token to login your user to your service with your own token. The login would essentially be your server verifying the Google token is valid (by contacting Google's servers) and then issuing its own token to be used for calls to your web services. If you don't like Google, you could use the Facebook SDK, etc.
As for what to use for tokens... The OAuth spec has stuff on that as well. You could do something as simple as a random string or something as complex as encrypted SAML assertions.
You should implement a token based OAuth, which will require the users to log in once, and then permanently have access.
You can use Google App Engine which already provides user authentication services for you (your Android users most likely already have google accounts) But this is only one of many options.
You can also look into Amazon's Identity Access Management (IAM) which will allow you to manage the users who have access to your web service, and authorize them accordingly.
I think the best way to do it is to use SSL (https), am I wrong?
This only prevents certain types of malicious use, but not everything. There is still nothing to prevent people from accessing your database on the phone, and retrieving credentials that way.

Categories

Resources