Failed OAuth2 with Google, via launchWebAuthFlow

3,426 views
Skip to first unread message

Cornel Chintoi

unread,
Jun 26, 2018, 6:01:18 AM6/26/18
to Chromium-Extensions-Announce
Hello,

I'm trying to authenticate using OAuth2 with a Google account. Currently I'm doing it like this:

            let AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
            let client_id = chrome.runtime.getManifest().oauth2.client_id;
            let redirect_uri = chrome.identity.getRedirectURL();  // of the form https://<extension-id>.chromiumapp.org/
            let scope = chrome.runtime.getManifest().oauth2.scopes.join(' ');
            let auth_params = {
                client_id,
                redirect_uri,
                response_type: 'token',
                scope
            };
            AUTH_URL += '?' + objToSearchParams(auth_params);

            chrome.identity.launchWebAuthFlow({
                url: AUTH_URL,
                interactive: true
            }, function(redirectURL: string) {
                if (chrome.runtime.lastError) {
                    console.error(chrome.runtime.lastError);
                } else {
                    let q = redirectURL.substr(redirectURL.indexOf('#') + 1);
                    let parts = q.split('&');
                    for (let i = 0; i < parts.length; i++) {
                        let kv = parts[i].split('=');
                        if (kv[0] === 'access_token') {
                            const token = kv[1];
                            console.log('token is', token);
                        }
                    }
                }
            });

When running this, in the background.js script, I'm getting an error of the form: {message: "Authorization page could not be loaded."}.
When navigating to the AUTH_URL I'm getting a more sensible error message: 400. That’s an error. Error: redirect_uri_mismatch.
The client_id that I used was copied from https://console.developers.google.com/apis/credentials/oauthclient/..., for a Chrome App(so not a Web Application, which has a client_secret-I also tried these ids, just to get an error about the client_secret not being an allowed param in the AUTH_URL-).
What am I doing wrong?

PS: I can't use the chrome.identity.getAuthToken flow because it is based on the account that's currently logged in in the Chrome browser(which requires periodical re-logins for accounts other than the one currently logged in into the browser).

Thank you in advance,

Rick Wessels

unread,
Jul 17, 2018, 8:31:27 AM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
he je bent gewoon een dikke lul als je dit ziet doe er maar niks aan hoor ik ben gehackt door een kind van 3 jaar


Message has been deleted
Message has been deleted

Ivor Padilla

unread,
Jul 17, 2018, 10:21:01 AM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
Try with:

chrome.identity.getRedirectURL("oauth2");

and the Authorized redirect  URI should be: 

https://<EXTENSION_ID>.chromiumapp.org/oauth2

> which requires periodical re-logins for accounts other than the one currently logged in into the browser

Correct me if I'm wrong but with launchWebAuthFlow the token expires after 3600 seconds and requires periodical re-logins as well. How do you go around this issue and generate a new token?

Ivor Padilla

unread,
Jul 17, 2018, 12:15:41 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
I answered my own question, here's the link if you're interested: https://stackoverflow.com/a/51385987/4932334

Cornel Chintoi

unread,
Jul 17, 2018, 12:43:22 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
Hello,

I'm using the flow involving "access_type": "online"(+ providing a stored "login_hint": "[e-mail of used account]", in case of token refresh). This has the advantage that it works directly with Google's servers(no backend involved), and also no "client_secret" exposed.

Ivor Padilla

unread,
Jul 17, 2018, 12:52:27 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
Can you post an example of your request params, if isn't too much to ask?

I also don't want client_secret exposed but that's the only way I managed to get a new token. I tried with access_code=online plus login_hint={user email} and I only get an object with access_token, expires_in and token_type without a refresh token.

Thank you.

Cornel Chintoi

unread,
Jul 17, 2018, 1:21:51 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
You'll have to refresh it periodically(after ~3600 sec, by checking the token validity against the /tokeninfo endpoint, described here-)(also remembering to add the "login_hint").

Ivor Padilla

unread,
Jul 17, 2018, 2:40:12 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
I'm curious why you're saying the login_hint is important if with these parameters I get a response back and a new token/code every time I request a token:

var auth_params = {
  client_id: chrome.runtime.getManifest().oauth2.client_id,
  redirect_uri: redirectURL,
response_type: 'code id_token token',
access_type: 'online',
};

Also, where do you get login_hint from? From a form field? 

Did you managed to solve your issue?

Cornel Chintoi

unread,
Jul 17, 2018, 3:38:26 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
"response_type" should be just "token"(since that is what you receive in case of "online" "access_type" anyway). For getting an access_token on the client-side the process goes like this:
-make request to Google's /auth endpoint(like you did above-you should look at the "prompt" param as well-);
-call /tokeninfo(to check for access_token validity, time until expiration, used account's email);
-store used account's email(chrome.storage.local/sync);
-[some time later-later than the expiration time from above-] call /tokeninfo => you'll get some error that the access_token is no longer valid;
-call /auth(but this time adding in the "login_hint": "[saved email]" param(this is done to auto-login/use the previously chosen account, so no more "Choose your account" popup);
-get the new(valid for another 3600 sec.) access_token(or an error).

The above process(which is an ok solution for my application) is not useful if you need to make requests to Google's API if the user is offline(in which case you would use the server-side flow, involving getting a "code" on the client-side, sending it to the backend, exchange it for an access_token & refresh_token-which you will need to store in a persistent way on your server-).

Ivor Padilla

unread,
Jul 17, 2018, 5:09:39 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
Thanks a lot for your help,

Just a few more notes:

As far as I know prompt is used to display a new consent screen every time the user hits 'login', if you don't want the consent screen just omit this param. Is that what you're referring to? https://developers.google.com/identity/protocols/OpenIDConnect#re-consent

Also if you call /auth with only "token" as 'response_type' you won't get an `id_token` and without it you won't be able to check the token with /tokeninfo because this endpoint requires an id_token.

:/

Sorry for being cocky but this is what I'm reading/testing.

Ivor Padilla

unread,
Jul 17, 2018, 5:58:34 PM7/17/18
to Chromium-Extensions-Announce, cornel....@gmail.com
I just re-read your answer and everything makes sense except for 'response_type' that imho needs to be set to 'token id_token' in order to get an id_token so we can validate the token via /tokeninfo endpoint.  I now get why you're recommending "prompt" in the first login.

Thanks a lot.

Cornel Chintoi

unread,
Jul 18, 2018, 12:44:44 AM7/18/18
to Chromium-Extensions-Announce, cornel....@gmail.com
I'm sending the access_token directly, like "https://www.googleapis.com/oauth2/v2/tokeninfo?access_token=[...]". And I use the old version of "prompt", "approval_prompt". But it's probably better to use the new API(v3) and the OpenID-compliant params.

Ivor Padilla

unread,
Jul 18, 2018, 6:59:53 AM7/18/18
to Chromium-Extensions-Announce, cornel....@gmail.com
That's really cool, TIL. id_token gives you a bit more of information like the nonce and the full name registered in the account which is great, but yeah access_token works perfectly with /tokeninfo too. Thanks for the advices.

Quan Gan

unread,
Feb 7, 2020, 4:06:02 PM2/7/20
to Chromium Extensions, cornel....@gmail.com
I followed your steps but was only able to get token with user interaction, when renewing token with login_hint set, I got the "user interaction required" error, this was using the `chrome.identity.launchWebAuthFlow` function. I also tried making ajax request instead of using the chrome api, but for security restriction there is no way to get the redirect URL. Wonder if you are still using the same steps in your app, does token refresh still work for you?

This thread has helped me to quite an extent, thank you!

Jason Savard

unread,
Jan 15, 2024, 3:48:33 AM1/15/24
to Chromium Extensions, Quan Gan, cornel....@gmail.com
I'm also getting this "user interaction required" when using interactive false with chrome.identity.launchWebAuthFlow did you manage to resolve this?
Reply all
Reply to author
Forward
0 new messages