Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron application using Google OAuth: "this browser or app may not be secure"

A user of my app reported an issue today about authorizing the user with Google (using OAuth 2.0). So far the application was opening a new BrowserWindow (node integration disabled, session is separated from the main application). You can see the implementation here since the library is OSS. I am using this to authorize the user to access application data on Google Drive. Today after logging in I see the following message:

This browser or app may not be secure.

Try using a different browser. If you’re already using a supported browser, you can refresh your screen and try again to sign in.

The learn more link has a section for developers. This section has 2 links. One is how to upgrade the application to PWA. Because the application is an API testing tool it won't be possible to run it in a web browser. The second link points to a document describing how to migrate to authorization for native application. However described flow requires authorization_code grant. This means I need to include OAuth secret into my application. Electron application, however, is still web application and there's no notion of compiling sources. I would expose client secret to the public which is not secured. Potentially I could build a server application to support it but the app is OSS project. It does not have funding to run a server for authorization.

My question is now how should I implement OAuth 2 for Electron application then. I can't use PWA's and server authorization flow (code grant) is far from ideal in this case.

like image 235
Pawel Psztyc Avatar asked Jan 10 '20 16:01

Pawel Psztyc


2 Answers

Warning: This answer relies on changing the browser's user-agent. As of Jan. 2021, Google disapproves of this and warns not to do this (see EDIT4). Use at your own risk!

The other answers didn't work for me (in Electron 9.0.5), but I eventually found this, which worked:

app.on("ready", ()=> {
    session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
        details.requestHeaders["User-Agent"] = "Chrome";
        callback({ cancel: false, requestHeaders: details.requestHeaders });
    });

    CreateMainWindow(); // your regular code to create root browser window
});

EDIT: Two other approaches, which I haven't tested, but which may also work:

app.on("ready", ()=>{
    session.defaultSession.setUserAgent("Chrome");
    ...
}
app.userAgentFallback = "Chrome";

EDIT2: Trying again sometime later, approach #2 did not work, but #1 still did. Haven't tried #3 yet.

EDIT3: Trying again later still, it seems that none of these workarounds are needed anymore! Google appears to accept sign-in popups from Electron apps again, without modifications to the user-agent. (odd that they'd revert this; perhaps I just did something wrong in my re-attempt)

EDIT4: While approach #1 still works atm, I recently found this blog post: https://developers.googleblog.com/2020/08/guidance-for-our-effort-to-block-less-secure-browser-and-apps.html Apparently Google is restricting usage of Google sign-in in non-standard browsers (which presumably includes Electron) starting in Jan. 2021, and warns developers not to modify their browser's user-agent (which all three of the possibilities I mention do). Use at your own risk! (they don't make clear what outcome will result, but for my own use, I'm opting to use the alternative shown below from now on)


As an alternative to using a Google sign-in popup in your app (which some might be wary of, since Electron apps could in principle insert code into the popup to read the raw password -- not that it matters that much, since Electron apps could just install keyloggers or the like anyway), you could instead open a tab in the user's regular external browser, pointed to a special page that triggers a sign-in popup there, and then just sends the credentials to your Electron app afterward.

Instructions can be seen here (approach 3): https://stackoverflow.com/a/64328193/2441655

like image 89
Venryx Avatar answered Sep 20 '22 03:09

Venryx


As Paweł explained, changing the user agent will do the trick. However, you can easily set the user agent by passing an object when loading the URL

win = new BrowserWindow({width: 800, height: 600});
win.loadURL(authUrl, {userAgent: 'Chrome'})

I have tested it and it worked like a charm

like image 21
Elmasry Avatar answered Sep 21 '22 03:09

Elmasry