simonw / google-drive-to-sqlite

Create a SQLite database containing metadata from Google Drive
https://datasette.io/tools/google-drive-to-sqlite
Apache License 2.0
152 stars 13 forks source link

OOB auth flow is scheduled for deprecation #39

Open simonw opened 2 years ago

simonw commented 2 years ago

Just learned about this: https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html?m=1#disallowed-oo

OAuth out-of-band (OOB) is a legacy flow developed to support native clients which do not have a redirect URI like web apps to accept the credentials after a user approves an OAuth consent request. The OOB flow poses a remote phishing risk and clients must migrate to an alternative method to protect against this vulnerability. New clients will be unable to use this flow starting on Feb 28, 2022.

...

  • Feb 28, 2022 - new OAuth usage will be blocked for the OOB flow
  • Sep 5, 2022 - a user-facing warning message may be displayed to non-compliant OAuth requests
  • Oct 3, 2022 - the OOB flow is deprecated for existing clients

From a comment on Hacker News: https://news.ycombinator.com/item?id=30417735

I'm using that flow here: https://github.com/simonw/google-drive-to-sqlite/blob/1215097786c0ecdb12a766c9f2c8e53b2b0cd0f9/google_drive_to_sqlite/cli.py#L56-L65

simonw commented 2 years ago

I could switch to the flow for TVs and limited input devices... https://developers.google.com/identity/protocols/oauth2/limited-input-device#identify-access-scopes - but that doesn't appear to allow the scope that I need! It allows:

But I use: https://www.googleapis.com/auth/drive.readonly

simonw commented 2 years ago

I think what I need to do is fire up a localhost web server and redirect back to that.

The announcement is a little confusing here because it mentions that option being disabled too - but actually they are only disabling that for "iOS, Android and Chrome app OAuth client types".

simonw commented 2 years ago

I always worry about starting a local server for this kind of thing because I want my tools to be usable on a remote server via SSH, where running a web server doesn't make sense since you can't easily run a localhost browser there.

I may have to recommend people create the auth.json file on their local machine with a browser and then scp it to their server to capture that case.

ncw commented 2 years ago

I always worry about starting a local server for this kind of thing because I want my tools to be usable on a remote server via SSH, where running a web server doesn't make sense since you can't easily run a localhost browser there.

What rclone does is provide a special mode rclone authorize to run locally to get the token only so users can but and paste that remotely.

I may have to recommend people create the auth.json file on their local machine with a browser and then scp it to their server to capture that case.

That is the other alternative which we call "copying the config" in the rclone world!

simonw commented 2 years ago

Here's a useful example of thehttp.server mechanism from the Python standard library (I'd like not to add another dependency just to handle this): https://github.com/nltk/nltk/blob/develop/nltk/app/wordnet_app.py

simonw commented 2 years ago

Prototype:

diff --git a/google_drive_to_sqlite/cli.py b/google_drive_to_sqlite/cli.py
index 9fe0358..8010d24 100644
--- a/google_drive_to_sqlite/cli.py
+++ b/google_drive_to_sqlite/cli.py
@@ -1,5 +1,6 @@
 from os import access
 import click
+from http.server import BaseHTTPRequestHandler, HTTPServer
 import httpx
 import itertools
 import json
@@ -123,6 +124,27 @@ def auth(auth, google_client_id, google_client_secret, scope):
         google_client_secret = GOOGLE_CLIENT_SECRET
     if scope is None:
         scope = DEFAULT_SCOPE
+
+    class MyServerHandler(BaseHTTPRequestHandler):
+        def do_GET(self):
+            sp = self.path[1:]
+            print(sp)
+            self.send_response(200)
+            self.send_header("Content-type", "text/html; charset=utf-8")
+            self.end_headers()
+            self.wfile.write(
+                """
+            <h1>Hello world</h1>
+            """.encode(
+                    "utf8"
+                )
+            )
+
+    server = HTTPServer(("127.0.0.1", 8182), MyServerHandler)
+    click.echo("http://127.0.0.1:8182")
+    server.serve_forever()
+    return
+
     click.echo("Visit the following URL to authenticate with Google Drive")
     click.echo("")
     click.echo(start_auth_url(google_client_id, scope))
simonw commented 2 years ago

Need to configure things in the console next.

willywongi commented 2 years ago

I run into your same issue within my project. Random stuff I'd love to share: