Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sign in to Google account with old password - how to redirect to blue Google Sign-In page?

Tags:

I’ve implemented the Google Sign-In SDK into my application and it works fine. When I click on the sign-in button, a window opens displaying the already stored accounts. Selecting one of those accounts successfully ends the sign-in process.

The one use case that does not pass is when the user gets to the sign-in dialog and clicks on an account that has an invalid password. I’m not sure how to solve this issue.


I followed with Google instruction "implement Sign-in SDK" and after calling those lines:

Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class); 

I catch exception with status code 12501 SIGN_IN_CANCELLED.

As I said before, it happens because one of the stored accounts has invalid password.

Here are the steps to reproduce:

  1. user logged in once
  2. dialog stored his credentials
  3. meanwhile user changed his account's password on www
  4. user selects saved credentials
  5. unrelated error code occurs).

How could I make user to redirect to this blue Google Sign-In page and keep the current flow?

For example, AliExpress somehow can handle this and redirects user to blue page with asking user to sign in again.

enter image description here

My code is not much different than in Google's instruction. This is my code flow. All start from onClick():

In onClick() method:

// Logout before all operations GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this); if (account != null) {     mGoogleSignInClient.signOut(); }  // Call to sign in Intent signInIntent = mGoogleSignInClient.getSignInIntent(); startActivityForResult(signInIntent, RequestCodes.RC_GOOGLE_SIGN_IN); 

In onActivityResult section:

@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {     Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");      if (requestCode == RequestCodes.RC_GOOGLE_SIGN_IN) {          try {              // Call to take account data             Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);              // Fetch account data             GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);              Account account = googleSignInAccount.getAccount();              // Calling to get short lived token             String shortLivedToken = GoogleAuthUtil.getToken(mContext, account, "oauth2:" + Scopes.PROFILE + " " + Scopes.EMAIL);              // Further calls here...          } catch (ApiException e) {              //https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInStatusCodes              if (e.getStatusCode() == 12501) {                 Log.e(TAG, "SIGN_IN_CANCELLED");             } else if (e.getStatusCode() == 12502) {                 Log.e(TAG, "SIGN_IN_CURRENTLY_IN_PROGRESS");             } else if (e.getStatusCode() == 12500) {                 Log.e(TAG, "SIGN_IN_FAILED");             } else {                 e.printStackTrace();             }          } catch (GoogleAuthException e) {             e.printStackTrace();         } catch (IOException e) {             e.printStackTrace();         }      } else {         super.onActivityResult(requestCode, resultCode, data);     } } 
like image 327
deadfish Avatar asked Feb 21 '19 16:02

deadfish


People also ask

How do I change the Google sign in page?

On your computer, sign in to Google. On the top right, select your profile image or initial. On the menu, select the account you'd like to use.

Why is Google changing its sign in?

To enhance the user experience by providing more security, Google has introduced a new way to login into their accounts. According to reports, a person having a Google account will need to go through a two-step verification (2SV) process.

How do I go to the Google sign in page?

On your computer, go to Gmail. Enter your Google Account email or phone number and password. If information is already filled in and you have to sign in to a different account, click Use another account.


1 Answers

Disclaimer I am not a Google employee. Everything I say below are my conclusions from investigating similar issues.

Short answer

You are doing everything right. It is the recommended way of logging into google account. Unfortunately there is no actual callback in this mechanism to specify what actually went wrong in your case. The way Google Play Services handles it is by notifying user that his credentials became obsolete by notificaion you can see below (right after the password was changed).

notification

I would recommend filing a bug for adding extra result codes for your case on https://issuetracker.google.com as it seems like a sensible improvement.

Long answer

Google uses Android account API just like everybody else (you can try it yourself). Behind the scenes it's just a oauth token retrieval and storage mechanism.

When the password was changed, the token is no longer valid and you get errors trying to use it.

The way it works is the way Google Play Services developers chose to implement it (hence I recommend you to file a bug).

For example, AliExpress somehow can handle this and redirects user to blue page with asking user to sign in again.

Aliexpress uses the deprecated API. As you can see the dialog for picking account has different color and no avatars. The API is is still usable, but may be shut down anytime (or not). I do not recommend you to use this, but here is how it works:

import com.google.android.gms.common.AccountPicker; import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.auth.UserRecoverableAuthException;  void chooseAccount() {     Intent signInIntent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);     startActivityForResult(signInIntent, REQ_CHOOSE_ACCOUNT); }  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {      if (requestCode == REQ_CHOOSE_ACCOUNT) {          String email = data.getExtras().getString("authAccount");         // better do this in background thread         try {             GoogleAuthUtil.getToken(this, new Account(email, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE), "oauth2:https://www.googleapis.com/auth/userinfo.profile");         } catch (UserRecoverableAuthException recEx) {             Intent recoverIntent = recEx.getIntent();             // Will redirect to login activity             startActivityForResult(recoverIntent, REQ_RECOVER);         } catch (Exception e) {             Log.d(TAG, "caught exception", e);         }      } } 

Hope it helps!

UPD: new Google Play APIs have ResolvableApiException, which extends ApiException you are catching. It has method startResolutionForResult() similar to the one used in older APIs. But the Bundle you receive contains no resolution info.

Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}] 

If you will file a bug, post it here, we will star it)

You can also show the "Choose account" dialog using default Android API (min API 23)

The code below may be sued to show a "choose account dialog" using default Android Account Management APIs. This is new and (hopefully) not going to be deprecated for a while.

import android.accounts.Account; import android.accounts.AccountManager;  // Unfortunately can be used only on API 23 and higher Intent signInIntent = AccountManager.newChooseAccountIntent(             null,             null,             new String[] { "com.google" },             "Please select your account",             null,             null,             new Bundle());  startActivityForResult(signInIntent, REQ_SELECT_ACCOUNT);  @Override     protected void onActivityResult(int requestCode, int resultCode, Intent data) {         super.onActivityResult(requestCode, resultCode, data);         if (requestCode == REQ_SELECT_ACCOUNT) {             String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);             String accountType = data.getExtras().getString(AccountManager.KEY_ACCOUNT_TYPE);             // now you can call GoogleAuthUtil as in example above         }     } 

You can also get list of Google accounts, visible to your app

Account becomes visible to your app after user have tried to sign in with that kind of account into your app, using one of the methods above. Event if sign in was not successful (e.g. password is expired), you will see this account in the list (won't be able to distinguish which one in case of multiple accounts though). So this may be used as workaround, but in a limited way.

import android.accounts.Account; import android.accounts.AccountManager;  try {         // requires android.permission.GET_ACCOUNTS         Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");         for (Account account : accounts) {             Log.d(TAG, "account: " + account.name);         }     } catch (Exception e) {         Log.i("Exception", "Exception:" + e);     } 

Conclusion Unfortunately I've found no other ways to access google account data to work around your case using modern Google Sign-In APIs. All advanced AccountManager APIs require you to have the same signature as account owner app (GMS - Google Mobile Services) which is not the case. So we can only request this from Google and hope for it to be implemented :(

like image 129
Amaksoft Avatar answered Oct 27 '22 00:10

Amaksoft