Allow file creation but not download with Google Drive API - google-api

I have an application that needs to upload file to Google Drive via the ordinary Google Drive API. It needs to upload, but it never needs to download anything, list directories, read metadata or anything like that. It basically uses Google Drive as a drop box to store results of some computations.
Because of the principle of least authority, I would like to give this application the authorization to create new files, but not read or modify anything. Is this possible? I cannot see anything like this in this list, so I suspect the answer is no, but would like more informed comments.

By principle of least authority "user/process should have necessities/privileges". A file created by an app is owned(create/modify/delete) by app and no access to rest of resources.
If this definition fits in your scope then use
https://www.googleapis.com/auth/drive.file
"Per-file access to files created or opened by the app"

As stated in Choose Auth Scopes
Auth scopes express the permissions you request users to authorize for your app. While many Drive apps can function with just the required set of scopes, you may need to consider using other available scopes.
As far as I know, you can choose from the list of scopes available for the Drive API, combine them or mix and match if necessary. And, you can also add other scopes if your app requires access to any other Google APIs as given in Google APIs scopes.
To learn more about scopes, you can watch the video of Google engineers discussing related tips and tricks within the given documentation. I hope that helps.

Related

Calendar API not auto accepting for new accounts

I generate a auth link like:
https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.events&prompt=consent&response_type=code&client_id=xxx&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fapplication%2Fsettings%2Fgcal&flowName=GeneralOAuthFlow
As you can see I call for the authorization as defined in the documentation here https://developers.google.com/calendar/api/guides/auth however, when I go to auth this is what I am presented with: and I thought this might be some new security thing from google but then I look at connecting to other sites and the account works just fine there.
This application is also fully verified for the consent screen.
While doing some comparison between my calls and other site's I notice that mine have /v2/ in the path while others do not. I have tried multiple individual google accounts with same result, but I always get a v2 redirect.
Anyone here know why this happens with v3 accounts and how I can solve it?
Unfortunately, this is the new default behaviour
It is realted to the new policy of More granular Google Account permissions with Google OAuth and APIs
It is being gradually introduced and is not related to either v2 or v3 accounts are being used but rather will eventually implemented for all accounts
Should the user not grant you all the scopes necessary for your Addon to run - you will need to handle it programmatically checking which scopes have been granted and requesting additional scopes if required
Best practive would be to make it very clear to your users PRIOR to the app installation that checking all checkboxes is crucial for the correct functionality of the app.
There is a very good stackoverflow post that explains the new change more in detail and includes many useful references.

How to "open" a file in a command line app using the drive.file scope

I have an internal app (not a published one, only used within our Google Workspace domain) which is a command line tool to update the contents of some Google Sheets. It currently uses the https://www.googleapis.com/auth/drive scope and works fine.
I want to minimize the privileges of the authorization token that this app caches, and by reading the documentation it seems that I should be able to use the https://www.googleapis.com/auth/drive.readonly scope to find the file I want, and also https://www.googleapis.com/auth/drive.file to grant write access to only a specific file.
With the reduced scopes, I am not surprised to get an error like:
appNotAuthorizedToFile: The user has not granted the app 566375348811 write access to the file 1UsItGhBHwRaodHbv5g1LCrSESUZBkskDvKDkbGjREjI
The only relevant documentation talks about integrating apps with Google Drive and using the Drive Picker UI which I expect does this authorization behind the scenes. Since this is an internal command line tool, I really don't want to go that route.
Hence the question:
How do I open a file in a command line application using the https://www.googleapis.com/auth/drive.file scope?
I'm OK even if I need to set some magic metadata on the file to make it accessible.
Update
As I got a couple of responses saying that when using drive.file it is not possible to access files which are not created by the application, I am putting some supporting documentation here to show why I think it is possible:
The API-specific auth info is the first document on the Google Drive API page, and it specifically mentions:
So, when possible, use non-sensitive scopes as they narrow access to
specific functionality needed by an app. In most cases, providing
narrow access means using the
https://www.googleapis.com/auth/drive.file per-file access scope.
Further down the page it mentions:
This scope enables users to select the specific files from Google
Drive, and through the Google Picker, that they want to allow your app
to access.
I understand this to mean that it is possible to open files which were not created by the app, even when using drive.file.
My problem is that the document goes on to explain:
Many apps work with per-file access without any changes. If you are
currently using your own file picker, we recommend switching to the
Google Picker which fully supports the drive.file scope.
Well, since I am using a command line app, I cannot use the Google Picker, so I am asking how to implement my own. I do understand that the picker itself needs to have access to all the files (hence the need for a drive.readonly scope), but to actually be able to write the files, it needs the elevated permission of drive or the more restrictive per-file access of drive.file.
If I simulate an authorization request for drive.file I get a prompt which explains that authorizing the request will grant my app to:
See, edit, create, and delete only the specific Google Drive files you use with this app ℹ️
Clicking on the information icon I get a more verbose explanation which reads like it support opening any file I authorize:
This app wants permission to create new files or change existing files
that you open with this app. Once authorized, the app can:
See these files
Upload and download these files
Delete these files
See the names and emails of people you share these files with
Share and stop sharing these files with others
Organize these files
There may be private information in your Google Drive, like financial
records, medical reports, photos or tax info.
There are also other examples of applications like ZIP Extractor or diagrams.net or Photo Editor which use the drive.file scope (based on the authorization prompt), and which I can use to open and edit files that were not created by them.
I am posting this as an answer, to demonstrate an ugly "workaround" for the issue.
TL;DR: Use a web based frontend to authorize access to files. Once the app is authorized, the command line app inherits the permissions.
More step by step instructions, assuming we already have a working command line project:
Go to https://myaccount.google.com/permissions and revoke all access I have granted to my app.
Follow the instructions at the Drive Picker API to update my current GCP project.
Create an API key. OK to be unrestricted, but I restricted it to https://localhost:9843
Create a new OAuth 2.0 client ID of a "Web application" type (my current one is "Desktop" type and that would not work). Authorize https://localhost:9843 as a JavaScript origin.
Copy the helloworld.html example at the bottom of the Drive Picker API guide which is also on GitHub with the following modifications:
Set developerKey to the API key created above
Set clientId to the new OAuth 2.0 client ID created abovce
Set appId to the numeric project ID of my GCP project
Add 'include_granted_scopes': true to the call to window.gapi.auth.authorize
Update createPicker to make it easier to find the files I want. E.g., set the mime type filter to application/vnd.google-apps.spreadsheet.
Host the example in a browser with ruby -rwebrick/https -e 'WEBrick::HTTPServer.new(:Port => 9843, :DocumentRoot => ".", :SSLEnable => true, :SSLCertName => "CN=localhost", :SSLCertComment => "Autogenerated" ).start'
Now, if my command line app fails to edit a file, I can use https://localhost:9843/helloworld.html to grant access to the file, and my command line app can then edit that file.
If you check the docs for the scope you will find it says.
https://www.googleapis.com/auth/drive.file View and manage Google Drive files and folders that you have opened or created with this app
This gives your app access to files that the app itself created or has previously opened.
You should also know that there is no way to limit authorization to a single file. Authorization is all or not thing.
How do I open a file in a command line application using the https://www.googleapis.com/auth/drive.file scope?
You make sure that the file was created by the app itself. using files.create. If the file was created by any other app the you cant access it using the drive.file scope
There is one note though if you have https://www.googleapis.com/auth/drive.read-only scope and you open that file to read it. the line where it says opened or created with this app implies to me that once you have opended it for read in this app that you would then be able to use it with https://www.googleapis.com/auth/drive.file but its not something I have tried.
Another thing is im not sure what you mean by open the google drive api is a file storage api its not going to let you see the contents of the file your going to have to download it and open it locally. Have you considered going though the Google sheets api if you want to read and write to it programmatically?

Which GSheet API should I pick to request consent

We have an application that needs to append data to users' designated Gsheet.
They should enter the sheet ID on our app, authorize it and then click export. Our app would then append a new row of data.
We are not clear what is the best or the necessary Oath 2 scope that is appropriate for that.
https://www.googleapis.com/auth/drive.file
or
https://www.googleapis.com/auth/spreadsheets
Any help is appreciated.
What you should do is check the documentation for what ever method you are trying to use. I am going to guess that you are using Method: spreadsheets.values.update
This method requires one of the following scopes
Which one you pick is up to you. They will both work. Technically if your not going to be accessing any of the google drive api methods then there's probably no reason to use the drive scope.
You can check the scopes#Sheets documentation for information on exactly what each scope gives you access to.
As you can see the sheets scope gives you access to all sheets a user has, while the drive.file scope will only give you access to files that where created by your app. Not just sheets.

How to give my application access to a publicly shared Google Drive file

I'm writing an application that downloads publicly shared Google Drive files. My application already knows the IDs of the files it needs to download. Here are three possible ways I can do this, and none of them are satisfactory:
1.) Downloading the file using the url https://drive.google.com/uc?id=<fileID>&export=download works, but is subjected to a severe rate limit restriction because the request is sent with no authentication.
2.) Downloading the file with https://www.googleapis.com/auth/drive.file authentication doesn't work. This is because the documentation says it only provides access to "files created or opened by the app".
3.) Downloading the file with https://www.googleapis.com/auth/drive authentication works (without any other code modifications from the "drive.file" case). I can't use this option because of the required security assessment for applications that use this scope.
The only way forward seems to be using "drive.file" authentication, where these files are opened by the app. How should I do this? I think the Picker API is the intended way to do this from inside an application, but I don't see support for filtering by a specific file ID, and I would prefer a solution that doesn't require user input, especially since options (1) and (3) don't require user input.
(as a side note, the logic behind this security policy doesn't make sense to me. If (2) is not possible because of a security/authentication concern, then (1) should not be possible. If (2) is not possible because of a rate limit concern, then (3) should not be possible. I have been told that this is intended behavior.)
I understand that you are developing a web app that downloads a publicly shared Drive file. If my assumption is correct, then you only need to implement an OAuth 2.0 protocol. You can follow the basic steps as a reference. Here is a more in depth guide for web apps. Please, ask me any question if you have doubts about this approach.
UPDATE
Based on this IssueTracker answer from Google, this is expected behaviour. That is, you need to open the public file in your app first and then you would be able to download it.

Simplest way authenticate with Python Google APIs to access own accounts

The main use case is using IPython as CLI to my own Google accounts. What I am really after is minmizing the fussing around between starting the IPython shell and actually issuing usefull calls against the API.
The docs for authenticating with Google APIs focus on setting up application which other user will use to access their data.
This leads to a lengthy Oauth dance involving a browser in order to allow other users to authenticate without compromising their credential.
However, I do not mind sharing my private credentials with myself. I am not planning on sharing the code. If I did share the code I would use something like dotenv to separate the credentials from the code.
Twitter provides developers a second set of credentials
that allows developers to access their own accounts for testing.
Thus it is possible to access ones own account programmatically
by just providing to sets of credentials: the developer credentials that allow the calls to the API and the other credentials that grant access to the developers own data. For example:
from twitter import *
t = Twitter(
auth=OAuth(token, token_key, con_secret, con_secret_key))
# Get your "home" timeline
t.statuses.home_timeline()
# Update your status
t.statuses.update(
status="Tweeting from Python")
Where con_secret* are the developer credentials and
and token* are the account access credentials.
How can I do something equally simple with Google APIs?
Where can I get credentials to access my own account?
How would I use them in Google API?
As an example what would be the simplest procedure for retrieving the contents from one of my own Youtube playlists?
I have com to think that a Python headless browser library could be give me what I need. I have asked a related question on SE Software Recommendations
https://softwarerecs.stackexchange.com/questions/35744/python-headless-browser-library-for-oauth2-authentication-from-ipython-console
I would like to download a set of credentials
Google offers this ability through it's client_secrets.json file. There are different ways to download this, depending on the type of account you want to use (Web application, installed application, Service account). The different techniques can be found here .
Store the credentials locally and keep using them without requiring
new credentials every call
This also isn't a problem, the client secret is valid until you renew it - AFAIK there is no automatic expiry unless you specify otherwise.
Once you have downloaded your client_secrets.json, store the file in a non-public directory (normally inside your project directory/config).
Similar to the downloading of the file, there are different techniques (flow classes) to use the JSON file depending on what type of account you are using. As an example, the below would be used for installed and web applications;
from oauth2client.client import OAuth2WebServerFlow
...
flow = OAuth2WebServerFlow(client_id='your_client_id',
client_secret='your_client_secret',
scope='scope URL here',
redirect_uri='http://example.com/auth_return')
Other flow class examples can be found here
Hope this helps - If you need further information, the official documentation (which be warned, can be incredibly inaccurate and confusing) can be found here https://developers.google.com/api-client-library/python/guide/aaa_oauth

Resources