Obtaining a basic google auth-token from AccountManager - android

I want to obtain a Google Authtoken from the AccountManager that I can send to my Webservice (not hosted on App Engine) to authenticate the User (I just need the email address and eventually his name, if no permission is required for this).
What do I have to use for the "authTokenType" Paramter of the "getAuthToken" method?
And which google Api do I have to use to get the Users Email?

This is doable using OpenID Connect, however it's sort of experimental, so details could change in the future. If you get an OAuth token for the 'https://www.googleapis.com/auth/userinfo.email' or 'https://www.googleapis.com/auth/userinfo.profile' scope you can use it to get user info from https://www.googleapis.com/oauth2/v1/userinfo (including email). Of course the user needs to authorize this.
You should theoretically be able to get the token from AcccountManager using the "oauth2:https://www.googleapis.com/auth/userinfo.profile" as the token type, but that doesn't appear to work on my device (Galaxy Nexus with stock 4.0.4). Since getting a token via the AccountManager doesn't work (at least for now), the only reliable way is to use a WebView and get one via the browser as described here: https://developers.google.com/accounts/docs/MobileApps
There is a demo web app here that does this: https://oauthssodemo.appspot.com
(late) Update: Google Play Services has been released and it is the preferred way to get an OAuth token. It should be available on all devices with Android 2.2 and later. Getting a profile token does work with it, in fact they use it in the demo app

I have had problems with this as well, since I was not able to find anything like a reference. Perhaps this can help you (code copied from an Android example on using the account manager):
Somewhere in an event handler of your Android app, issue a request for an auth token to get the user's email address in Android:
_accountMgr = AccountManager.get(this);
Account [] accounts = _accountMgr.getAccounts();
Account account = accounts[0]; // For me this is Google, still need to figure out how to get it by name.
_accountMgr.getAuthToken(account, AUTH_TOKEN_TYPE, false, new GetAuthTokenCallback(), null);
In the callback, extract the access token:
private class GetAuthTokenCallback implements AccountManagerCallback<Bundle> {
public void run(AccountManagerFuture<Bundle> result) {
Bundle bundle;
try {
bundle = result.getResult();
final String access_token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
// store token somewhere you can supply it to your web server.
} catch (Exception e) {
// do something here.
}
}
}
Make some request to your web server, supplying the access token.
On the web server, validate the access token and obtain the email address:
curl -d 'access_token=<this is the token the app sent you>' https://www.googleapis.com/oauth2/v1/tokeninfo
You should get something like this:
{
"issued_to": "<something>.apps.googleusercontent.com",
"audience": "<something>.apps.googleusercontent.com",
"scope": "https://www.googleapis.com/auth/userinfo.email",
"expires_in": 3562,
"email": "<users email address>",
"verified_email": true,
"access_type": "online"
}
or if something went wrong:
{
"error": "invalid_token",
"error_description": "Bad Request"
}

You can get the User's name with the Google+ People API. (It will not provide the user's email address).
If this is OK, you can use "Know who you are on Google" as the authTokenType.
There is a sample application provided by Google that demonstrates how to use the AndroidAccountManager in conjunction with the Google+ APIs.
Link: http://code.google.com/p/google-plus-java-starter/source/browse/#hg%2Fandroid

Related

Android login via Google Sign-In with a Spring Boot backend

As the title says, I'm trying to use the Google Sign-In API with a Spring Boot backend server, as described here.
Just to describe the context, the Spring backend is basically a resource+authentication server, that is currently providing Oauth2 authentication to a second spring boot application containing the frontend website, via Google SSO or simple form login (similar to what's described here).
My original idea was to mimic the #EnableOauth2Sso annotation by simply providing an access token to the android app and attach it to every request as "Bearer ".
Using the user credentials for this was pretty straightforward: I simply make a request to the server at "/oauth/token", using those credentials inserted by the user as authentication and I correctly receive the access token.
Now, I have absolutely no idea on how to build a similar procedure with the Google API in Android. The tutorial page I linked before describes how to get a token ID and how the server should validate it, but after that I don't know what to do.
So far I've managed to add a filter to the security chain that simply checks the token like this:
private Authentication attemptOpenIDAuthentication(#NonNull String tokenString){
String clientId = authServices.getClientId();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, factory)
.setAudience(Arrays.asList(clientId, androidClient))
.build();
try {
GoogleIdToken token = verifier.verify(tokenString);
if (token != null) {
return authServices.loadAuthentication(token.getPayload());
} else {
throw new InvalidTokenException("ID token is null");
}
} catch (GeneralSecurityException | IOException e) {
throw new BadCredentialsException("Could not validate ID token");
}
}
This manages indeed to create an Authentication object, but how can I generate an access token after the authentication filtering?
To recap, so far I've got:
The Android app successfully retrieves the Google token ID and sends it to the server
The server sucessfully intercepts the request and validates the token
I'm basically missing the third point where I return a proper access token to the Android client.
Here you are a simple scheme to better understand the situation:
Is there any other way to validate the token and get an access token from the server, or should I completely change the authentication procedure on Android?
As far as I can tell: Yes, you need an access token from the server. If I understand this correctly, a webapp is already authenticated via Oauth on your backend, so the procedure is similar here: Load the user with the google-ID and generate a token. In my application I used a JWT which is valid for 30 days. If the token expires, the Google authentication in the app is usually still valid, so the token can be renewed using the Google ID. With Oauth you can also send a refresh-token directly.
It is important that the app always checks the Google authentication first and only in a second step that of the backend.
For the Authentication process on the backend u may need to manually implement a dedicated securityConfiguration for this. Have a look at the jhipster project, they implemented a custom jwt-authentication which may give you an idea how it works.

Azure Mobile Apps - Android Authentication getting additional information

I am currently at a loss on how to proceed with my app.
I currently authenticate following the tutorial here and everything works swimmingly.Azure Mobile Apps Authentication
Where I am at a loss is how to use the id and/or token that is stored following this process to obtain basic profile information say a users email or their profile photo.
From what I have read online this is merely a azureId that stored not the google profile ID which I would use with the google+apis.
Has anyone got a reference that shows a novice programmer how to get the email address or userId required to use the google api.
The only reference I can find is a blog post from 2014. Surely there must be an easier way. And one specifically written to work on Mobile apps as opposed to mobile services. Blog post describing how to expand on authentication with google on mobile services which is no use
Here is my process
// We first try to load a token cache if one exists.
Log.v(TAG, "Click"+USERIDPREF );
if (loadUserTokenCache(mClient))
{
Log.v(TAG, "table" +mClient.getCurrentUser().toString());
createTable();
returnHome();
}
// If we failed to load a token cache, login and create a token cache
else
{
// Login using the Google provider.
final ListenableFuture<MobileServiceUser> mLogin = mClient.login(MobileServiceAuthenticationProvider.Google);
Futures.addCallback(mLogin, new FutureCallback<MobileServiceUser>() {
#Override
public void onFailure(Throwable exc) {
Log.v(TAG, "Login On fail " +exc.getMessage() );
}
#Override
public void onSuccess(MobileServiceUser user) {
Log.v(TAG, "On Success" );
createTable();
cacheUserToken(mClient.getCurrentUser());
Log.v(TAG, "On Success" + mClient.getCurrentUser() );
returnHome();
}
});
}
The first documentation link you posted has the answer. From https://azure.microsoft.com/en-us/documentation/articles/app-service-authentication-overview/#working-with-user-identities-in-your-application:
Code that is written in any language or framework can get the information that it needs from these headers. For ASP.NET 4.6 apps, the ClaimsPrincipal is automatically set with the appropriate values.
Your application can also obtain additional user details through an HTTP GET on the /.auth/me endpoint of your application. A valid token that's included with the request will return a JSON payload with details about the provider that's being used, the underlying provider token, and some other user information. The Mobile Apps server SDKs provide helper methods to work with this data. For more information, see How to use the Azure Mobile Apps Node.js SDK, and Work with the .NET backend server SDK for Azure Mobile Apps.
So to summarize, you have different options depending on which language you use, but the most cross-platform option is to send an authenticated request to your mobile app's /.auth/me endpoint. You'll get back a JSON object which contains a bunch of user claims (name, provider-specific ID, email, etc.).

How AccountManager knows what Google account to use?

I am trying to implement Google rest api for Drive V3 in Android.
But I am getting authError
{
"error":{
"errors":[
{
"domain":"global",
"reason":"authError",
"message":"Invalid Credentials",
"locationType":"header",
"location":"Authorization"
}
],
"code":401,
"message":"Invalid Credentials"
}
}
I use AccountManager to get token from user, and I think it access the wrong console account.
How does it know what account to access?
This is my AccountManager code, I successfully get user token. Also I invalidate it before with AccountManager.invalidateAuthToken
Bundle options = new Bundle();
options.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, context.getPackageName());
accountManager.getAuthToken(account, scope, options, context,
callback, null);
As per the Account Manager docs for [getAuthToken](http://developer.android.com/reference/android/accounts/AccountManager.html#getAuthToken(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback, android.os.Handler)):
Gets an auth token of the specified type for a particular account, prompting the user for credentials if necessary. This method is intended for applications running in the foreground where it makes sense to ask the user directly for a password.
If a previously generated auth token is cached for this account and type, then it is returned. Otherwise, if a saved password is available, it is sent to the server to generate a new auth token. Otherwise, the user is prompted to enter a password.
It seems that it may depend on the value of your account variable that you are passing in the getAuthToken().
You probably already have this in, but gonna included in for the community, did you include the USE_CREDENTIALS permission as mentioned in the docs:
NOTE: If targeting your app to work on API level 22 and before, USE_CREDENTIALS permission is needed for those platforms.
Hope this helps. Good luck. :)

GoogleAuth access token is missing the userinfo.profile scope

I have an android app that uses the Google Plus API and I also ask for an access token which I pass to my server so I can make oauth 2.0 API calls to get user details.
I ask for an access token using GoogleAuthUtil.getToken with the following scopes:
String scopes = "oauth2: https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/plus.login" ;
then, I pass the access token I get to my server, and make an api call to: https://www.googleapis.com/oauth2/v2/userinfo
which returns the following user details: [id, email, verified, name, given_name, family_name, link, picture, gender, locale]
so far so good.
This works 90% of the time. Lately I've been getting users that don't have most of the details. When I examine their access token I see the following:
{
"issued_to": "534771845378-a8epgha85s5hkr3bqnsj8ihjvpl8pms.apps.googleusercontent.com",
"audience": "534771845378-ha8epgha85s5hkr3bqnsj8ihjvpl8pms.apps.googleusercontent.com",
"user_id": "103098746579631883577",
"scope": "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email",
"expires_in": 3382,
"email": "***#***.com",
"verified_email": true,
"access_type": "offline"
}
Notice that the userinfo.profile scope is suddenly missing. Any thoughts on why this could happen on occasions?
It is probably because more and more information is being stored in a Google+ Profile, which has different access controls, and not the older user profile.
You can get their public profile information with the plus.login scope using the https://www.googleapis.com/plus/v1/people/me endpoint, but this will only be if they have made their information public. You will also not be able to get their email using this endpoint - you'll still need to use the oauth userinfo endpoint.
See https://developers.google.com/+/api/latest/ for further details and other available endpoints.

Using authToken for Google Health Data

We have developed and published an app for Google Health. Now we want to avoid every time logging into the gmail account by asking username and password.
So as to do this i have heard that I can have following options.
1. OAuth
2. Account Manager
3.
The problem with OAuth is that it will go via Android -> Web App -> Health path so i will need to develop an web app as well which we dont wish to do it right now.
So I am trying to use Account Manager, here is my code with which I could get list of accounts and an valid authToken for the selected account.
AccountManager mgr = AccountManager.get(getApplicationContext());
System.out.println("Got account manager");
Account[] accts = mgr.getAccounts();
}
Account acct = accts[0];
AccountManagerFuture<Bundle> accountManagerFuture = mgr.getAuthToken(acct, "android", null, this, null, null);
Bundle authTokenBundle = accountManagerFuture.getResult();
System.out.println("Account name "+accts[0].name);
String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
System.out.println("Got token:"+authToken);
But now I am confused about how to use this token to access the health data.
For getting the demographic feed we used the following code,where we explicitly made user to login into our application.
String queryURL = "https://www.google.com/health/feeds/profile/ui/" + profileId +"/-/DEMOGRAPHICS";
getDemoGrInfoQuery = new Query(new URL(queryURL));
Feed dempGrResultFeed;
globals = new Globals();
dempGrResultFeed = healthService.query(getDemoGrInfoQuery, Feed.class);
And thus we used to get the Feed using the URL.
And now I want to skip the login process and use the above authToken for retrieving the feed. How can this be done?
Any help would be really appreciated!!!
Thanks in advance,
As the standard OAuth procedure is supposed to work, you open the OAuth URL in a WebView (or anything similar) with all the required parameters, users provide Google (not your app) with their user name and password, then google gives you a token which you can use for your future communications.
This way the user doesn't have to give you their login credentials. They give it only to google, and google gives you a token which will authenticate your app every time you use it.
I think you should be good to go with this, since it requires you to open a WebView only once, unless the user logs out of google using your application or denies access to your application.
After getting the token, you just start polling google with that token and never ask user for their login credentials. quite seamless.
UPDATE
After our conversation in chat, let me tell you that you'll have to register an application with google, which will give you an appID, this appID will be used by your Android app to tell google that it is requesting permission on behalf of the Application which this appID refers to.
UPDATE 2
open the Google OAUth with all the parameters, google will give you a code
use that code and create a POST request again to google, and google will now return a long lasting AccessToken
You can then use this AccessToken in all your future communications

Categories

Resources