4
votes

I'm a web developer and i'd like to access to the Google APIs from my business software, I've created a Drive account and I'd to create a folders and files via code (VB.NET). I'm following the documentation, I've created a JWT (Json Web Token), I've used a Service Account and I've obtained an Access Token.

Now I'd like to access to the Google APIs. Using a console application, I created some folders, and I can get a list of created folders via code. But I cannot see those folders in my Google Drive account. How is it possible?

Here is the request I send to the server in order to show the folders and files list: https://www.googleapis.com/files/{FILE_ID}?key={API_KEY}

I obtain a JSON string as response, with the informations relating the FILE_ID elements. e.g.:

{ "kind":"drive#file", "id":"FILE_ID", "mimeType":"application/vnd.google-apps.folder"(if is a folder) / "FILE_MIMETYPE"(if is a file), "title":"FOLDER_NAME" / "FILE_NAME", ... }

And here is the code I used to access to Google APIs: (VB.NET)

...

Public Function browseFile(ByVal fId As String) As List (Of FileSourceElement)

  Dim webclient As New WebClient()
  webclient.Headers.Add("Authorization", " Bearer " & _accessToken)
  webclient.Headers.Add("X-JavaScript-User-Agent", "Google APIs Explorer")
  Dim res As String = webclient.DownloadString("https://www.googleapis.com/drive/v2/files?key=" & _apiKey).Trim()

  'res contains the JSON with the informations of the file/folder 
  ...

End Function

Public Sub createContainer(ByVal path As String)
  Dim webclient As New WebClient()
  webclient.Headers.Add("Authorization", " Bearer " & _accessToken)
  webclient.Headers.Add("X-JavaScript-User-Agent", "Google APIs Explorer")
  webclient.Headers.Add("Content-Type", "application/json")
  webclient.UploadString("https://www.googleapis.com/drive/v2/files", _ 
                     "POST", _ 
                     "{""title"":""daEliminare2"", ""parents"":[{""id"":""" & path & """}], ""mimeType"":""application/vnd.google-apps.folder""}")
End Sub

...

In my Google Drive I haven't MANUALLY created a folder and I haven't MANUALLY uploaded a file, i must do all the operation only via code.

As I said to you, I've successfully created a folder and I printed successfully the list of file (via code), but in my GDrive the elements created by UI don't appear. Why?


I've read that in the Service Account, in order to get the Access Token it's required a special JSON string called Json Web Token (JWT) composed by an header, a claim set and a signature (base64 string). The string is:

{base64 formatted JWT header}.{base64 formatted JWT claimSet}.{base64 formatted JWT signature}

My JWT is:

Header

{
  "alg": "RS256",
  "typ": "JWT"
}

Claim set { "iss": "[email protected]", // where '0123456789' is the CLIENT_ID. "scope": "https://www.googleapis.com/auth/drive", "aud": "https://accounts.google.com/o/oauth2/token", "exp": timeStamp + 3600, //where 'timeStamp' is the number of seconds since 1970-01-01T00:00:00. "iat": timeStamp }

To write a signature I've followed the procedure descripted in this page:

https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature

Once I've written the JWT I send it to the server and I get a JSON string as response in this mode:

{
  "access_token": "ACCESS_TOKEN", // (e.g.: 1/8xbJqaOZXS...)
  "type_token": "Bearer",
  "expire_in": 3600
}

When I obtain the Access Token (AT), I use it to access to the Google APIs; for example: if I would show all list of files and folders, I send a request that has an header like this:

Authorization: Bearer AT X-JavaScript-User-Agent: Google APIs Explorer

url: https://www.googleapis.com/drive/v2/files?key={MY_API_KEY}

But I underline that in the list there are some items (using the VB.NET console application), while there aren't any in my Google Drive.

So I got the Access Token but I don't succeed to access to the Google APIs.

PS: I need access to the Google APIs without use any browser.

Part second:

I've read that in the Service Account, in order to get the Acces Token it's required a special JSON string called Json Web Token (JWT) composed by an header, a claim set and a signature (base64 string). The string is:

{base64 formatted JWT header}.{base64 formatted JWT claimSet}.{base64 formatted JWT signature}

My JWT is:

Header

{
  "alg": "RS256",
  "typ": "JWT"
}

Claim set { "iss": "[email protected]", // where '0123456789' is the CLIENT_ID. "scope": "https://www.googleapis.com/auth/drive", "aud": "https://accounts.google.com/o/oauth2/token", "exp": timeStamp + 3600, //where 'timeStamp' is the number of seconds since 1970-01-01T00:00:00. "iat": timeStamp }

To write a signature I've followed the procedure descripted in this page:

https://developers.google.com/accounts/docs/OAuth2ServiceAccount#computingsignature

Once I've written the JWT I send it to the server and I get a JSON string as respoonse in this mode:

{
  "access_token": "ACCESS_TOKEN", // (e.g.: 1/8xbJqaOZXS...)
  "type_token": "Bearer",
  "expire_in": 3600
}

When I obtain the Access Token (AT), I use it to access to the Google APIs; for example: if I would show all list of files and folders, I send a request that has an header like this:

Authorization: Bearer AT X-JavaScript-User-Agent: Google APIs Explorer

url: https://www.googleapis.com/drive/v2/files?key={MY_API_KEY}

But I underline that in the list there are some items (using the VB.NET console application), while there aren't any in my Google Drive.

So I got the Access Token but I don't succeed to access to the Google APIs.

PS: I need access to the Google APIs without use any browser.

Many thanks and best regards

MP

4

4 Answers

6
votes

Since you are using a Service Account, all the folders and files will be created in this Service Account's Drive which cannot be accessed through a web UI and will be limited to the default quota.

To add content in a user's Drive, you will need to go through the regular OAuth 2.0 flow to retrieve credentials from this user. You can find more information about OAuth 2.0 on this pages:

2
votes

If you would like to see the files under a User Account without using OAuth 2.0, then you can give the Service account edit permission to a folder under the User Account.

Then when uploading the file using the Service Account make sure you set Parent Reference ID to use that folder ID

The folder ID is determined in the address bar

Hope this helps.

0
votes

Was not aware of the given solution. I did differently by adding a file permission, after having added the file (NodeJS code. insertFile is called after a classic fileUpload by the user) :

insertPermission = function(fileId, value, type, role,authClient,cb) {
  var body = {
    'value': value,
    'type': type,
    'role': role
  };
  var request = drive.permissions.insert({
    'fileId': fileId,
    'resource': body,
    'auth': authClient
  }, function (err,response) {
    cb(err,response);
  });
}

exports.insertFile = function(file,customer,callback) {
    exports.authorize(function (err,authClient) {
        drive.files.insert({
          resource: {
            title: file.name,
            mimeType: file.mimeType,
            parents: [{id:customer.googleDriveFolder}]
          },
          media: {
            mimeType: file.mimeType,
            body: file.buffer
          },
          auth: authClient
        }, function(err, response) {
          debug('error:', err, 'inserted:', response.id);
          if (!err) {
            insertPermission(response.id,customer.email,"user","writer",authClient,function (err,resp){
              callback(null, resp);            
            });
          }
        });
    });
};

Note that i'm using JWT with private key kind of authentication, with a service account :

exports.authorize = function(callback) {
    if (_tokens && ((_tokens.expiry_date - (new Date()).getTime())>100 )) callback(null, _authClient);
    else {

    var scope = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.appdata', 'https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.file','https://www.googleapis.com/auth/drive.metadata',
'https://www.googleapis.com/auth/drive.metadata.readonly',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/drive.scripts'];

    var authClient = new google.auth.JWT(
            '<myServiceAccountClientId - [email protected]>',
            '<path to key>.pem',
            ''); //seems we could use an user to impersonate requests, i need to test that..
    authClient.authorize(function(err, tokens) {
        if (err) {
            callback(err);
            return;
        }
        callback(null,authClient);    
    });
    }
};
0
votes

You can see your files uploaded using API. Use follwing URL to see all your files.

https://drive.google.com/folderview?id=XXX

Where XXX= Folder ID created using API. Debug code to get folder id,

But to work above link you have to provide permission after creating any folder or file as below:

 Permission newPermission = new Permission();
 newPermission.Value = "[email protected]";
 newPermission.Type = "anyone";
 newPermission.Role = "reader";
 _service.Permissions.Insert(newPermission, NewDirectory.Id).Execute();

Alternate Link to See UI : https://drive.google.com/drive/folders/XXX