I've been trying to implement an app which saves user accounts (id, password and token) with the Android AccountManager. Been using this as my reference for implementing the functionality.
I am able to show my AuthenticationActivity and create accounts (which show up correctly in the Settings > Accounts after I create them). After I add a new account I try to immediately login the user with the token received which I save with setAuthToken(). However this never works and I see that the authToken is always null. I then have to run the app for a second time and login again after which it works.
The code where I add a new account (from my signup activity) is,
private void addNewAccount(final AccountManager am, final String accountType, String authTokenType) {
Log.d(TAG, "addNewAccount(): " + accountType + ", " + authTokenType);
am.addAccount(accountType, authTokenType, null, null, this, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
final String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Log.d(TAG, "addNewAccount() -> bundle = " + bundle + ", authToken = " + authToken);
if (!TextUtils.isEmpty(authToken)) {
startLoggedInActivity(authToken);
} else {
Log.d(TAG, "token is null"); // <- always get here
}
} catch (Exception e) {
e.printStackTrace();
}
}
}, null);
}
And the code where I finish the login (after I receive the token and add the new user) is,
private void finishLogin(Intent intent) {
Log.d(TAG, "finishLogin(): " + intent.getExtras());
if (intent.hasExtra(KEY_ERROR_MESSAGE)) {
Toast.makeText(getBaseContext(), intent.getStringExtra(KEY_ERROR_MESSAGE), Toast.LENGTH_SHORT).show();
setResult(RESULT_CANCELED, intent);
} else {
String accountName = intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
String accountPassword = intent.getStringExtra(PARAM_USER_PASS);
final Account account = new Account(accountName, intent.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE));
if (getIntent().getBooleanExtra(ARG_IS_ADDING_NEW_ACCOUNT, false)) {
String authtoken = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN);
// Creating the account on the device and setting the auth token we got
// (Not setting the auth token will cause another call to the server to authenticate the user)
mAccountManager.addAccountExplicitly(account, accountPassword, null);
Log.d(TAG, "finishLogin() -> addAccountExplicitly: " + account + ", " + accountPassword);
mAccountManager.setAuthToken(account, mAuthTokenType, authtoken);
Log.d(TAG, "finishLogin() -> setAuthToken: " + authtoken);
} else {
mAccountManager.setPassword(account, accountPassword);
Log.d(TAG, "finishLogin() -> setPassword: " + account + ", " + accountPassword);
}
setAccountAuthenticatorResult(intent.getExtras());
setResult(RESULT_OK, intent);
}
finish();
}
Does anyone know what the problem could be (been struggling with this for quite some time now :( )?
Related
How can I validate the Access Token and how to get the information of token using Access Token?
Is this the url to validate the Access Token?
https://mydomain/oauth2/v1/tokeninfo?access_token=tYPJr7F6ArYkd1Vdlh1gbhWlnz8NLA9TZmky2NpvaHZxhw14udbmFNRG1pKMKVEY&token_type=bearer
Here is an example of the data taken from token (the example is from Azure auth - but it does not matter both use OAuth2).
That's how you extract the information from the Token:
in getAuthInteractiveCallback() or getAuthSilentCallback() methods:
private AuthenticationCallback getAuthSilentCallback() {
return new AuthenticationCallback() {
#Override
public void onSuccess(AuthenticationResult authenticationResult) {
/* Successfully got a token, call api now */
Log.d(TAG, "Successfully authenticated");
Log.d(TAG, "ID Token: " + authenticationResult.getIdToken());
Log.d(TAG, "ID Token: " + authenticationResult.getAccessToken());
try {
String token = authenticationResult.getIdToken();
String token2 = token.substring(token.indexOf('.') + 1, token.lastIndexOf('.'));
byte[] data = Base64.decode(token2, Base64.DEFAULT);
String text = new String(data, StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(text);
JSONArray jsonArray = new JSONArray(jsonObject.getString("emails"));
String eMail = jsonArray.get(0).toString();
Log.d(TAG, "eMail: " + eMail);
} catch (JSONException ex) { }
authResult = authenticationResult;
state.setAuthResult(authResult);
}
#Override
public void onError(MsalException exception) {
}
#Override
public void onCancel() {
}
};
}
In addition you can get iod, expiration time (exp), auth time (auth_time), versiov (ver)
I'm currently creating a test application to test using the latest facebook SDK to update our existing application problem is that I need to get the user birthday. I'm confused on this since the the SDK3 and above provides more information than the updated SDK4 and I'm lost on how to get the birthday as all the answers I've seen so far doesn't provide the birthday on my end. Here's my code so far:
LoginButton CallBacks:
fbLogin = (LoginButton) findViewById(R.id.login_button);
fbLogin.setReadPermissions(Arrays.asList("email", "user_birthday"));
fbLogin.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
// App code
GraphRequest request = GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(JSONObject object, GraphResponse response) {
try {
if (object.has("id"))
id = object.getString("id");
if (object.has("name"))
userName = object.getString("name");
if (object.has("email"))
userEmail = object.getString("email");
if (object.has("gender"))
gender = object.getString("gender");
if (object.has("birthday"))
birthday = object.getString("birthday");
String profile_URL = "https://graph.facebook.com/" + id+ "/picture?type=large";
LogCat.show(id + "\n" + userName + "\n" + userEmail + "\n" + birthday + "\n" + profile_URL + "\n" + gender);
} catch (Exception e) {
e.printStackTrace();
LogCat.show("Error:" + e.getMessage());
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "id, name, email,gender, birthday");
request.setParameters(parameters);
request.executeAsync();
}
#Override
public void onCancel() {
// App code
Toast.makeText(SplashLogin.this, "CANCEL", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(FacebookException exception) {
// App code
Toast.makeText(SplashLogin.this, "" + exception.toString(), Toast.LENGTH_SHORT).show();
}
});
The JSON response returns only the ID and name, email and gender of my account but doesn't include the birthday. Did I missed out something?
According to the latest sdk of facebook, to get birthday you need to first submit your application for review. On test applications you can just get the public profile which includes the following things
id
cover
name
first_name
last_name
age_range
link
gender
locale
picture
timezone
updated_time
verified
For more information you can read the following documentation from this link
If your app requests this permission Facebook will have to review how
your app uses it. link
Facebook don't give user birthday by default.You have to use extended permissions.
I solve this problem by enable permission of Birthday in my app from the Facebook Developer Console.
fbSignUp.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(final LoginResult loginResult) {
// App code
GraphRequest request = GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onCompleted(JSONObject object, GraphResponse response) {
try {
Data.fbAccessToken = loginResult.getAccessToken().getToken();
LogCat.show(loginResult.getAccessToken().getToken());
if (object.has("id")) {
id = object.getString("id");
Data.fbId = object.getString("id");
}
if (object.has("name")) {
userName = object.getString("name");
;
Data.fbUserName = object.getString("name");
}
if (object.has("email")) {
userEmail = object.getString("email");
Data.fbUserEmail = object.getString("email");
}
if (object.has("birthday")) {
userBirthDay = object.getString("birthday");
}
else {
if (userEmail == null || "".equalsIgnoreCase(userEmail)) {
if (userName != null && !"".equalsIgnoreCase(userName)) {
userEmail = userName + "#facebook.com";
Data.fbUserEmail = Data.fbUserName + "#facebook.com";
} else {
userEmail = id + "#facebook.com";
Data.fbUserEmail = Data.fbId + "#facebook.com";
}
}
}
} catch (Exception e) {
e.printStackTrace();
LogCat.show("Error:" + e.getMessage());
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "id, name, email,birthday,gender");
request.setParameters(parameters);
request.executeAsync();
}
#Override
public void onCancel() {
// App code
Toast.makeText(RegisterScreen.this, "CANCEL", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(FacebookException exception) {
// App code
Toast.makeText(RegisterScreen.this, "" + exception.toString(), Toast.LENGTH_SHORT).show();
}
});
i am using twitter integration using fabric, now issue is i am able to get all the details of user except email address. following is my code, can any one help me with that
public void login(Result<TwitterSession> result) {
//Creating a twitter session with result's data
TwitterSession session = result.data;
//Getting the username from session
final String username = session.getUserName();
//This code will fetch the profile image URL
//Getting the account service of the user logged in
Call<User> userResult = Twitter.getApiClient(session).getAccountService().verifyCredentials(true, false);
userResult.enqueue(new Callback<User>() {
#Override
public void failure(TwitterException e) {
}
#Override
public void success(Result<User> userResult) {
User user = userResult.data;
String twitterImage = user.profileImageUrl;
try {
Log.d("imageurl", user.profileImageUrl);
Log.d("name", user.name);
System.out.println("Twitter Email"+user.email);
//Log.d("email", user.email);
Log.d("des", user.description);
Log.d("followers ", String.valueOf(user.followersCount));
Log.d("createdAt", user.createdAt);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
This is how I fetched the user email of an user:
final TwitterSession twitterSession = result.data;
twitterAuthClient.requestEmail(twitterSession, new com.twitter.sdk.android.core.Callback<String>() {
#Override
public void success(Result<String> emailResult) {
String email = emailResult.data;
// ...
}
#Override
public void failure(TwitterException e) {
callback.onTwitterSignInFailed(e);
}
});
So you have to call TwitterAuthClient.requestEmail() once you got a successful Result<TwitterSession> upon authorization.
Be aware that you'll have to contact Twitter support to enable access to users' email for your app. An error message with this will show up.
Here is my code to get details from twitter:
private void intializeTwitterUI() {
loginButton = (TwitterLoginButton)
findViewById(R.id.twitter_login_button);
loginButton.setCallback(new Callback<TwitterSession>() {
#Override
public void success(Result<TwitterSession> result) {
// The TwitterSession is also available through:
// TWITTER.getInstance().core.getSessionManager().getActiveSession()
TwitterSession session = result.data;
// TODO: Remove toast and use the TwitterSession's userID
// with your app's user model
String msg = "Twitter: #" + session.getUserName() + " logged in! (#" + session.getUserId() + ")";
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
/**
*
*/
AccountService _AccountService = Twitter.getApiClient(result.data).getAccountService();
_AccountService.verifyCredentials(true, true).enqueue(new retrofit2.Callback<User>() {
#Override
public void onResponse(Call<User> call, retrofit2.Response<User> response) {
Log.d(TAG, "Twitter user is: " + response.toString());
Log.d(TAG, "Twitter-Email" + response.body().email);
Log.d(TAG, "Twitter-profileImage" + response.body().profileImageUrl);
Log.d(TAG, "Twitter-ID" + response.body().id);
twitterDetails = response.body().email + "," + response.body().profileImageUrl + "," + response.body().id;
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Log.e(TAG, "verifyCredentials failed! " + t.getLocalizedMessage());
}
});
}
For those that want to do it with Kotlin can try in this way:
val session = TwitterCore.getInstance().sessionManager.activeSession as TwitterSession
val authClient = TwitterAuthClient()
authClient.requestEmail(session, object : Callback<String>(){
override fun failure(exception: TwitterException?) {
email.setText("Welcome to Twitter")
}
override fun success(result: Result<String>?) {
email.setText("Welcome " + result?.data)
}
})
It is possible to request an email address from users, but it requires your app to be whitelisted.
check here Is there a way to get an user's email ID after verifying his/her Twitter identity using OAuth?
My goal is to log into a BaaS with the Google plus sdk, the BaaS requires a tokenId via googleSignInAccount.getIdToken() and an accessToken.
GoogleAuthUtil.getToken(activity, accountName, scopes); is depreciated, and was used to get the accessToken.
GoogleAuthUtil.invalidateToken(activity, token); is also depreciated.
What is the alternative way to get the accessToken and invalidate(is invalidation needed now)?
I am aware of and have tried:
GoogleAuthUtil.getToken(Context, Account, String);
and
GoogleAuthUtil.clearToken(activity, token);
Account seems to require a first part permission(thus not an option) Ex. account = new Account(googleSignInAccount.getEmail(), "com.google"); nor do I know if clear is synonymous with invalidate(seems to work with the depreciated method however, I don't know the repercussions), or if there are some other call/api's to use.
Like from:com.google.android.gms.auth.api.Auth
Google developer site has a page on migrating from GoogleAuthUtil.getToken
https://developers.google.com/identity/sign-in/android/migration-guide
This code is no longer complaiming of using depreciated API
private void loginInBackendless(final GoogleSignInAccount acct) {
Log.d(TAG, "handleSignInResult: try login to backendless");
//final MainActivity mainActivity = (MainActivity)this.getActivity();
//final String accountName = acct.getEmail();
final String scopes = "oauth2:" + Scopes.PLUS_LOGIN + " " + Scopes.PLUS_ME + " " + Scopes.PROFILE + " " + Scopes.EMAIL;
final FragmentActivity fragmentActivity = this;
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String token = null;
try {
token = GoogleAuthUtil.getToken(fragmentActivity, acct.getAccount(), scopes);
GoogleAuthUtil.clearToken(fragmentActivity, token);
handleAccessTokenInBackendless(acct.getIdToken(), token);
} catch (UserRecoverableAuthException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (Exception e) {
e.printStackTrace();
}
return token;
}
};
task.execute();
}
Here is my code for facebook me request.i want to get user email and other basic info.this code is work without any issue in emulator.but in real device email gives null value. id,fristname... comes with real values. how can i get email on real device?
Request request = Request.newMeRequest(session,
new Request.GraphUserCallback() {
#Override
public void onCompleted(GraphUser user, Response response) {
if (user != null) {
RequestParams params = new RequestParams();
params.put("email",(String) user.getProperty("email"));
params.put("password", "");
params.put("facebook_id", user.getId());
editor.putString("facebook_id", user.getId());
login(params,
(String) user.asMap().get("email"),
user.getId(), user.getFirstName(),
user.getLastName());
}
}
});
Bundle params = new Bundle();
params.putString("fields", "id,email,first_name,last_name");
request.setParameters(params);
request.executeAsync();
Instead of submitting a ME request, use Facebook's LoginButton, and add a hook to intercept the user info:
// Intercept the facebook user returned from login
facebookLoginButton.setUserInfoChangedCallback(new LoginButton.UserInfoChangedCallback() {
#Override
public void onUserInfoFetched(GraphUser user) {
mFacebookUser = user;
if (user != null) {
LogUtils.LOGFB(TAG, "Got a Facebook user: " + user.getFirstName() +
" " + user.getLastName() + ", email: " + user.getProperty("email"));
}
else {
LogUtils.LOGFB(TAG, "No Facebook user");
}
}
});
Then add an extra permission to get email:
facebookLoginButton.setReadPermissions(Arrays.asList(
"email", "user_birthday", ...));