I have an android application connected to an appengine backend through endpoints. I would like the application to know the user's google account name and I wondered if there was an easy way, without going through all the authentication procedure described here
I don't really care about the security stuff at the moment, I would just like, for example, to be able to say "hello" to the user by using his name, or to store in the datastore a list of usernames that used the application. And I don't want users to be forced to enter a password to use my app.
I tried to use the code
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this, "appname.appengine.com");
String try= credential.getSelectedAccountName();
inside OnCreate() but it gives an null result. I also tried to put
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
inside the endpoint, but it doesn't work either.
Any help? Thanks in advance!
You can use the account manager to get the users' account w/o actually authenticating the accounts, e.g.:
// Requires android.permission.GET_ACCOUNTS
AccountManager manager = AccountManager.get(ctx);
Account[] accounts = null;
try {
accounts = manager.getAccounts();
} catch (SecurityException e) {
Log.i(CTAG, "Unable to read due to SE");
}
if (null != accounts)
for (Account account : accounts)
Log.v(CTAG, "New account =" + account.name + ", " + account.type );
This should satisfy your requirement to store a list of the users who used your app.
However, this does not give you the actual name of the user for greeting them. To get the users' name you need to use the profile API that was added with ICS (and which requires READ_PROFILE permission). You can get their name here:
http://developer.android.com/reference/android/provider/ContactsContract.CommonDataKinds.StructuredName.html
Related
I have an Android app that is deployed to Android Enterprise users in my company through the managed Play Store. Every user has a work profile on their device. The email address of this account is the user's work email address.
The app needs to access the user's work email address in order to sync user data to the server.
On devices running versions of Android prior to 8 (Oreo), this code works great:
AndroidManifest.xml
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Code
public String getUserEmail() {
AccountManager manager = AccountManager.get(this);
Account[] accounts = manager.getAccounts();
List<String> emails = new ArrayList<String>();
// On Oreo+, the length of accounts is 0.
for (Account account : accounts) {
if (account.name.endsWith("#companyname.com")) {
emails.add(account.name);
}
}
if (!emails.isEmpty() && emails.get(0) != null) {
return emails.get(0);
}
return null;
}
In Oreo and above, the result of AccountManager.getAccounts() is always of length zero.
This behavior change is documented by Google: (https://developer.android.com/about/versions/oreo/android-8.0-changes.html#aaad). The GET_ACCOUNTS permission is no longer sufficient to retrieve accounts and we have to use AccountManager.newChooseAccountIntent().
This is undesirable because I don't want to let the user choose a non-work account to use with this app. I only want their work email address.
Is there a way for an Android Enterprise app to obtain the user's work email address without using AccountManager.newChooseAccountIntent()? Is there a way for the EMM administrator to make this property available to the application through the Android Enterprise SDK? Or is there another way to obtain the user's work email address?
I've integrated Google+ sign-in in my Android application. Now I wan't to get the user's friend list and store it on the server. I can't get the friends list on the client app and send it to the server since the data can be easily tampered. So I thought about generating an access token using the following code and send it to the server, which the server will then use to query the Google+ API and get the user's friends.
String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Account account = new Account(accountName, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
String scope = "oauth2:" + Constants.SCOPE_PLUS_LOGIN + " " + Constants.SCOPE_EMAIL;
try {
String accessToken = GoogleAuthUtil.getToken(getApplicationContext(), account, scope);
} catch (IOException | GoogleAuthException e) {
e.printStackTrace();
}
But is sending the access token to the server directly using https safe enough? Cause if the token is compromised then any third party can use it to steal the user's personal information.
Or is there any better way to fetch and store the signed in user's friend list on the server?
1) Always transfer access_tokens over HTTPS.
2) Don't build any way to get access_tokens from your server. Make sure the server only supports sending access_tokens to it.
3) access_tokens expire after one hour so the window for abuse is limited.
As the title says, when I try to request to get the friends list with the field installed:
"me/friends?Fields=installed&access_token=..."
I get the following error in my logcat:
"Invalid OAuth access token"
When looking on the facebook api I see that installed needs to take an application access token. So I generated the application access token using the appId and app Secret using:
https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=APP_ID&client_secret=APP_SECRET
Below is the code:
try {
JSONObject obj = Util.parseJson(mFacebook.request("me/friends?fields=installed&access_token=..."));
Log.d("json Response", obj.toString());
JSONArray array = obj.optJSONArray("data");
if (array != null) {
for (int i = 0; i < array.length(); i++) {
// String name = array.getJSONObject(i).getString("name");
String id = array.getJSONObject(i).getString("id");
Log.d("Friends: ",id);
}
}
}catch (Exception e){
Log.d("Friends:", e.getMessage());
}
Any one any ideas why its doing this I have been searching for ages.
Cheers
What you are getting after authentication is App Access Token.
Quoting : Authenticating as an App allows you to obtain an access token which allows you to make request to the Facebook API on behalf of an App rather than a User. This is useful, for example to modify the parameters of your App, create and manage test users, or read your application's insights for example. App access tokens can also be used to publish content to Facebook on behalf of a user who has granted a publishing permission to your application
from facebook docs.
What you need for your case is an user access token. Refer this.
A user needs to authenticate and grant access to your app for you have access to his friends list.
EDIT
For checking for a single user the url is
https://graph.facebook.com/{uid}?fields=installed&access_token=< ACCESS_TOKEN >
You are trying to get user friend list and then check if the app is installed. I don't think getting user friend list is possible without user access token.
EDIT 2
Assuming from your comment that you have the list of frind's. Then you need not call for each user instead you can use FQL.
https://graph.facebook.com/fql?q=SELECT uid,is_app_user from user where uid IN (uid1,uid2)
And if you have the user access token then you can directly do.
https://graph.facebook.com/fql?q=SELECT uid,is_app_user from user where uid IN (SELECT uid2 FROM friend WHERE uid1 = me())
Hope this solves your problem.
Don’t request /me/friends – because with an app access token the API won’t know who „me” is supposed to be – request /userid/friends instead.
Sorry, I was wrong before – the way to go is with an user access token, and just setting the request up against /me/friends…
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
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