12

My Google Drive-integrated web application works fine with the drive scope, but using such a broad scope is bad practice unless necessary. I would like to restrict the scope to drive.file so that I can only access files created by the application and files opened using Google Picker, but I cannot get it to work.

Files created by the application can be opened without problem. Files opened using Google Picker, however, are not accessible; attempting to download such a file results in a 404 error. When I right-click the file in Google Drive and select "View authorized apps", my application is not listed as one of the authorized apps.

The code works fine if the scope is expanded to drive.

I have written a minimal test page that should download a file selected by the user in Google Picker. The process can be started by calling auth() followed by showPicker(). The key parts of the code are as follows:

gapi.auth.authorize({
    client_id: '123456789012.apps.googleusercontent.com',
    scope: 'https://www.googleapis.com/auth/drive.file',
    immediate: false
});

...

var picker = new google.picker.PickerBuilder()
    .setAppId('123456789012')
    .addView(new google.picker.DocsView(google.picker.ViewId.DOCS_IMAGES))
    .setOAuthToken(gapi.auth.getToken().access_token)
    .setCallback(onPickerAction)
    .build();
picker.setVisible(true);

...

function onPickerAction(data) {
    if ( data.action === google.picker.Action.PICKED ) {
        var id = data.docs[0].id;
        var request = new XMLHttpRequest();
        request.open('GET', 'https://www.googleapis.com/drive/v2/files/' + id);
        request.setRequestHeader('Authorization', 'Bearer ' + gapi.auth.getToken().access_token);

        request.addEventListener('load', function() {
            var item = JSON.parse(request.responseText);
            console.log(item);
        });

        request.send();
    }
}

A related question concluded that the app ID was improperly set. That does not seem to affect me; I have tested all combinations I can think of without any luck.

Community
  • 1
  • 1
Jakob
  • 2,588
  • 5
  • 27
  • 34
  • If it's this easy, I got lucky in the docs. Looking at : https://developers.google.com/picker/docs/index#gdata , it appears that `scope` is set to an array, not a flat string, such as : `scope: ['https://www.googleapis.com/auth/photos']`. Does your code work if you change it to : `scope: ['https://www.googleapis.com/auth/drive.file'],` ? – Anthony Dec 25 '13 at 15:39
  • Also, I'm not totally clear on how scopes work, but while I see the `drive.file` scope listed as a Google Drive scope, it's not listed in the Google Picker scope subset : https://developers.google.com/picker/docs/index#otherviews Is it possible that the issue is simply that `drive.file` is not an available scope for `pickerBuilder()`? Trying to hack around from the console, `gapi.auth.getToken()` returns null, breaking `showPicker()`. But that may be for other reasons... – Anthony Dec 25 '13 at 15:59
  • Okay, so it was failing from console because `auth()` uses a popup, which needed to be unblocked. After granting, I got the following with `showPicker()` : `Unable to post message to https://docs.google.com. Recipient has origin http://rpg-ambience.com. Invalid 'X-Frame-Options' header encountered when loading 'https://docs.google.com/picker?': 'ALLOW-FROM http://rpg-ambience.com' is not a recognized directive. The header will be ignored.` But the picker did load, and there was no download, but the console logged the file object details with `downloadItem`, so try `scope:['blah']` – Anthony Dec 25 '13 at 16:13
  • Did you ever succeed in getting picker to work with drive.file scope? – pinoyyid Jan 11 '14 at 09:42
  • 1
    @pinoyyid: Nope, no luck so far. I considered starting a bounty but I'm not sure it will help since this is so API-specific. Posting to the official Google Drive developer community did not yield any solution either: https://plus.google.com/108061244596087600297/posts/YcdzVtnXkta – Jakob Jan 11 '14 at 18:47
  • @pinoyyid: After a new suggestion in the Google+ conversation, the problem is now fixed and I've added the solution as an answer here. – Jakob Feb 15 '14 at 23:49

3 Answers3

5

The Google+ plus conversation mentioned in OP's answer held the keys for me. There are a number of things that have to be configured correctly to get this to work:

  1. Drive API and Drive SDK are both enabled for your developer account.
  2. The appId set on the picker matches the first portion of the clientId, e.g. ('1932384883' in '1932384883-qI99fef9f9ghh9n99vvsqa9zxczx8cz8xcc.googleusercontent.com')
  3. In the Drive SDK configuration, define an Open URL. The URL doesn't have to exactly match the URL from which the picker is opened, but the origin (e.g. https://domain.com) does.
  4. In the "Client ID for web applications" section, the Open URL above must also be in the list of redirect URIs. The origin must be in the list of javascript origins.
  5. You may also have to require the user to have 'installed' your app into Google Drive, or requested the 'drive.install' scope as well as 'drive.file'

A subset of the above may work, but this is what I needed to set up in order for a simple REST request for the picked file to come back with a 200 rather than a 404.

alalonde
  • 1,823
  • 1
  • 16
  • 27
  • The Drive SDK is no longer there, and has been folded into Drive API, but the Open URL setting is still there and needs to be set, and you also need to add an icon in order to save the Open URL setting. It's in the third tab of the Drive API settings. – Benjamin Atkin Jun 19 '18 at 22:26
  • 3
    Calling `.setAppId()` was critical for me to get this working on a domain that was different from the Open URL. – Femi Jul 11 '19 at 16:16
  • @Femi Can't upvote your comment enough, setAppId was the key for me as well. – Elliott Darfink May 07 '20 at 09:26
1

As first suggested in a Google+ conversation, the problem can be solved as follows:

  1. Make sure that the Drive SDK is enabled in the Google developer console (the Drive API is something else, and only having that enabled is not enough).
  2. Specify an "Open URL" for your application.
Jakob
  • 2,588
  • 5
  • 27
  • 34
  • @bamnet: I haven't tried that yet, unfortunately. Are you having problems with it? – Jakob May 21 '14 at 12:40
  • The Drive SDK is no longer there, and has been folded into Drive API, but the Open URL setting is still there and needs to be set, and you also need to add an icon in order to save the Open URL setting. It's in the third tab of the Drive API settings. – Benjamin Atkin Jun 19 '18 at 22:25
0

In addition to setting the app ID, make sure the page you're serving the picker on is listed in your javascript origins in the APIs console. Both the app ID and the origin need to match for files to be authorized.

Steve Bazyl
  • 11,002
  • 3
  • 21
  • 24
  • For this test page, I have provided the app ID as a sequence of numbers given as a string (my client ID without `.apps.googleusercontent.com`) and my origin in the API console as `http://rpg-ambience.com`. Would that be correct for this scenario? – Jakob Oct 02 '13 at 21:03