Our production Android application uses Chrome Custom Tabs for OAuth login
It was working fine yesterday when Chrome version was 61.0.3163.98
Following an overnight update of Chrome to 72.0.3626.76 the Login process gets stuck in the embedded browser and the user is presented with a blank white screen.
If we uninstall the Chrome update the login starts to work again
What has changed with Chrome and/or Chrome Custom Tabs that breaks our login process?
If I switch my default browser to Firefox my apps login works fine.
In fact if I change default browser to anything other than chrome it works fine, even Opera works, although Opera doesnt show an embedded browser.
It also works when I uninstall the Chrome update and revert back to chrome version 61.0.3163.98
Further Details:-
Step 1). Load URL with prompt=none and my custom scheme Redirect URL.
Step 2). My App receives a NEW INTENT containing the auth code.
Step 3). I attempt to access my back end APIs with this code, which fails with 400
Step 4). Load URL prompt=login and my users are presented with a sign in screen where they enter their credentials and click on the Sign In button.
Step 5). NOTHING HAPPENS, the user is presented with a blank screen, my app does not receive a NEW INTENT.
Heres the code I employ to open the Login URL via a Chrome Custom Tab
private void openCustomTab() {
codeVerifier = generateRandomCodeVerifier();
checkCodeVerifier(codeVerifier);
codeChallenge = deriveCodeVerifierChallenge(codeVerifier);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, getURL(PROMPT_NONE));
}
The above code loads the URL with prompt=none and it also specifies my custom scheme redirect url.
My Android app receives a New Intent in onNewIntent that contains an authCode, I attempt to retrieve an access token with this authocode which fails with 400.
I then use custom Tabs to load a second URL with prompt=login as follows:-
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setToolbarColor(Color.BLUE);
final CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(SignInActivity.this, getURL(PROMPT_LOGIN, authCode));
By loading this URL with prompt=login the user can enter their credentials and click on the Sign In button.
Its at this point the Chrome Custom Tab gets stuck.
here are the network calls I capture using Stetho, the last call made is authorization.ping that shows as cancelled
I have found a resolution for this issue as follows:-
I added an additional prompt of "consent" to the existing prompts of "none" then "login".
Now the user see a consent screen titled
oauth.approval.page.template.title
where the user sees a list of choosable options including
ACCESS TO YOUR DATA
SIGN IN WITH OPENID CONNECT
OPENID CONNECT PROFILE SCOPE
OPENID CONNECT EMAIL SCOPE
at the bottom of this screen theres two options
oauth.approval.page.template.allow
oauth.approval.page.template.dontAllow
when the user selects
oauth.approval.page.template.allow
they can now proceed into the android app.
The only issue is the user sees this approval screen whenever they log in
I have recently answered this same question, I believe the update with chrome adds some security layer. I also had same issue before with different browser (stock browser that comes with different non-officials Custom ROMS) and I think we're not safe in case other browsers implement the same behavior.
To avoid all these problems, I would suggest that you implement a staging page that will serve to handle all your OAuth2 redirects.
This solution also has the advantage of avoiding for the user to "Allow" login every time.
You can find a detailed answer here: How to implement OAuth single Sign In/Sign Out with Chrome Custom Tabs
The only change that has been made on that update is the break/removal of HPKP ( HTTP-Based Public Key Pinning)
HTTP-Based Public Key Pinning (HPKP) was intended to allow websites to send an HTTP header that pins one or more of the public keys present in the site's certificate chain. Unfortunately, it has very low adoption, and although it provides security against certificate misissuance, it also creates risks of denial of service and hostile pinning. For these reasons, this feature is being removed.
You are getting the 400 Bad request because of that, Thats just my guess.
If all goes well, the Bundle
contains a valid token in the KEY_AUTHTOKEN
key using token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
from the AccountMangerCallback
and you're off to the races
Authentication with OAuth2 services has been changed on developer.android.com, it is required to request an auth token again, some of the authenticators are requiring a direct interaction with the user before giving a valid token.
try and run AccountManager or whatever API you're implementing to get KEY_INTENT
before you get clientID, clientSecret, granting type, or your redirectURI
check the following link and adopt any new implementations: https://developer.android.com/training/id-auth/authenticate
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With