Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't gmail oauth work in my Android app?

I'm working on an app which does an oauth2 authentication which used to work, but unfortunately doesn't work anymore. As far as I know (but not 100% sure) nothing changed on the code, so I don't know why it wouldn't work anymore.

The app creates a webview and loads an url from our server, which redirects it to google to authenticate on this url (just changed client id and my domain):

https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=1234567890-XXXXXXX.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Fexample.com%3A5000%2Fchannel%2Fgmail%2Fcallback&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&access_type=offline

which immediately redirects it to:

https://accounts.google.com/ServiceLogin?passive=1209600&continue=https://accounts.google.com/o/oauth2/auth?access_type%3Doffline%26scope%3Dhttps://www.googleapis.com/auth/userinfo.email%2Bhttps://www.googleapis.com/auth/gmail.readonly%26response_type%3Dcode%26redirect_uri%3Dhttp://example.com:5000/channel/gmail/callback%26client_id%3D123456789-XXXXX.apps.googleusercontent.com%26hl%3Dnl%26from_login%3D1%26as%3D-2178738b5063e716&ltmpl=popup&oauth=1&sarp=1&scc=1

The same system is used from our iOS-app, which works like a charm. So there's nothing wrong with our server implementation. After the webview redirected to google, it automatically returns back to the app without showing any google screen. I'm using the following code to open the webview:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_browser_webview, container, false);

    webView = (WebView) view.findViewById(R.id.web_view);

    webView.getSettings().setJavaScriptEnabled(true);
    webView.getSettings().setDisplayZoomControls(false);
    webView.getSettings().setLoadWithOverviewMode(true);
    webView.getSettings().setUseWideViewPort(true);
    webView.getSettings().setDomStorageEnabled(true);

    webView.setWebViewClient(new WebViewClient() {
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            Log.wtf("ERROR", description + " " + failingUrl);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            Log.wtf("WEBVIEW URL", url);
            if (url.contains(Api.API_ENTER_POINT)) {
                // We never actually get here
                getActivity().finish();
            }

            return false; //Allow WebView to load url
        }
    });
    if (userId != null & userToken != null) {
        Log.d("Gmail login", String.format(Api.API_GMAIL,userId,userToken));
        webView.loadUrl(String.format(Api.API_GMAIL,userId,userToken));
    }
    return view;
}

and the logcat output is as follows:

02-29 18:56:39.028 27510-27510/com.example D/Gmail login: http://example.com:5000/api/v1/channel/gmail/on/1/CAAV8cDYVv9wBAKDfKu7zjInpUbSxBjSiouG8iFtP2EGKjb63AOAjirFf9SepSwe62PsNt0pflwZBKs8xvoH2Y7cnOsHTC33ikbwLFgwiqmK7AtHYzo2BTZAmiDGQvCKZBSdjIR5o5zvgqSZAFiGEU10PVTnXw2fRJzukQ0VEVoZC9VrO7el8hjeg2VoVBFhb9ppPCsHYkPKRWgThKJ76VJS4K3m2X7LwZD
02-29 18:56:39.092 27510-27510/com.example D/cr_Ime: [ImeAdapter.java:358] onViewFocusChanged: gainFocus [true]
02-29 18:56:39.119 27510-27510/com.example D/cr_Ime: [ImeAdapter.java:140] onCreateInputConnection returns null.
02-29 18:56:39.162 27510-27510/com.example I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@2b109b89 time:227199315
02-29 18:56:39.163 27510-27510/com.example A/WEBVIEW URL: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=1234567890-XXXXXXXXXX.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Fexample.com%3A5000%2Fchannel%2Fgmail%2Fcallback&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&access_type=offline
02-29 18:56:39.216 27510-27510/com.example A/WEBVIEW URL: https://accounts.google.com/ServiceLogin?passive=1209600&continue=https://accounts.google.com/o/oauth2/auth?access_type%3Doffline%26scope%3Dhttps://www.googleapis.com/auth/userinfo.email%2Bhttps://www.googleapis.com/auth/gmail.readonly%26response_type%3Dcode%26redirect_uri%3Dhttp://example.com:5000/channel/gmail/callback%26client_id%3D1234567890-XXXXXXXXXX.apps.googleusercontent.com%26hl%3Dnl%26from_login%3D1%26as%3D-231b0767e02a8ca9&ltmpl=popup&oauth=1&sarp=1&scc=1
02-29 18:56:39.283 27510-27510/com.example I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@16bf8d10 time:227199436
02-29 18:56:39.287 27510-27510/com.example D/cr_Ime: [ImeAdapter.java:358] onViewFocusChanged: gainFocus [false]
02-29 18:56:39.287 27510-27510/com.example D/cr_Ime: [ImeAdapter.java:326] hideKeyboard
02-29 18:56:39.288 27510-27510/com.example D/cr_Ime: [InputMethodManagerWrapper.java:56] isActive: false

Since this log doesn't really give an error, I'm unsure what could be wrong.

Does anybody have any idea what could possible be wrong or how I can debug this? All tips are welcome!

like image 334
kramer65 Avatar asked Feb 29 '16 18:02

kramer65


People also ask

How does OAuth work for mobile apps?

OAuth is an authorization framework that enables you to work with external systems in a secure way using digital identifiers called tokens. One type of token is called an access token . Its function is to allow you to exercise APIs securely.

Which OAuth type is appropriate for mobile apps?

The Authorization Code Grant flow is recommended for applications that have a web service. This flow requires server-to-server communication using an application's client secret. Note: Never put your client secret in distributed code, such as apps downloaded through an app store or client-side JavaScript.

How do I enable OAuth?

Go to the Google API Console OAuth consent screen page. Add required information like a product name and support email address. Click Add Scope. On the dialog that appears, select the scopes your project uses.


1 Answers

You're code most likely stopped working because of an update in some part of the API's that you are using; I'm guessing it could be updating from OAuth to OAuth2, or possibly a simple patch update. The easiest fix would be to add uses permissions and metadata to your AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>

<meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />

If that doesn't fix it, there is most likely a bigger problem at hand.

According to this post, it is better to use onCreate() for doing any non-graphical initializations, since it is called before onCreateView(). In order to be able to login to google, as stated in this post, you first need to select an account from the device like so (put this in your Main.java or MainActivity.java):

public static AccountManager accountManager;
accountManager = AccountManager.get(this);
Account[] accounts = accountManager.getAccountsByType("com.google");

Then, you need to get the token from the selected account like so:

private void onAccountSelected(final Account account) {
    accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, this, new AccountManagerCallback<Bundle>() {
        public void run(AccountManagerFuture<Bundle> future) {
            try {
                String token = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
                useToken(account, token);
            } catch (OperationCanceledException e) {
                onAccessDenied();
            } catch (Exception e) {
                handleException(e);
            }
        }
    }, null);
}

Then, once you authenticate the Token and Account, you will be able to login to google using OAuth2 (Refer to the OAuth2 GitHub Source for the authentication code).

If you're still having problems and/or I didn't fully answer your question, check out this on how to use OAuth2 with AccountManager and API calls, or this on how to use OAuth2 with WebView. The latter probably pertains more to your needs. Both give entire example files on how to do what you're looking for.

If even after reading the two links above you still need help or have a question or concern, feel free to leave a comment!

like image 157
Arastais Avatar answered Nov 12 '22 22:11

Arastais