Unable to get Google Drive file parents using API key - google-api

I am trying to move Google Drive file (Google Sheet/Google Document) from Shared Team Drive to another Shared Drive but my Service account is failing to get file filed parents from v3.
I've tested with the Playground and noticed that "parents" field is only returned when you are Authenticated with Google OAuth 2.0 BUT NOT when you are using API Key (or in my case Service auth file).
https://developers.google.com/drive/api/v3/reference/files/get
parents screenshot
no parents screenshot
Working fine with My Drive but not when returning parents for Shared Drive files.
// My Google Client is initialised
const googleClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
['https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/calendar']
);
// Google Drive v3
const googleDrive = google.drive({
version: 'v3',
auth: googleClient
});
// Getting File details
const file = googleDrive.files.get({
fileId,
fields: '*',
supportsTeamDrives: true
});
Can you help me with any ideas or explain me the difference in the API responses?

API Keys get their permissions based on the project permission (and other settings on the Cloud Console).
OAuth authenticates as the current user and is able to access the APIs as that user would.
You can read more about that here.
In this case, the Try It Feature does not have an API key able to access the methods you are trying to execute.
Hope this helps!

Related

Get Google Sheet Data using V4 API without OAuth

Using this nodeJS example, I could get the data from a public sheet.
But how do I get the data from a non-public sheet owned by me (my google a/c) ?
Is there some way to send in the username and password as arguments ?
I don't want OAuth way as I want the data to be pulled from the sheet & displayed on a public webpage.
The other option I can think of is to have OAuth2 done once write a script to handle refresh tokens automatically as a cron every hour ?
Since this is a file that you the developer own i would recommend using a service account
If you share the file with the service account it will then have permissions to access it without you needing to go though the oauth2 steps of authorizing your application.
On google cloud console simply create Service account credentials
const {google} = require('googleapis');
const auth = new google.auth.GoogleAuth({
keyFile: '/path/to/your-secret-key.json',
scopes: ['https://www.googleapis.com/auth/spreadsheets'],
});
Then change your auth code slightly. Open the service account key file and look for the service account email address its the only one witha # in it. Share the file with the service account like you would any other user in google drive web app.
Once it has access you shouldn't need to authorize the app again.
I have a video on Google drive API upload file with Nodejs + service account which might help you a bit you just need the authorization code. Everything else you have should work as is.

Use a service account to get the list of users from Google domain

Hello all.
I have been assigned the task of fetching unanswered emails from the inbox of each member of our Google domain using Spring Boot, but I haven't been able to do it.
In first place, I need the list of users from the domain. This can be achieved via Directory API (which cannot be enabled by that name in the Google Developer console, by the way. Looks like it belongs to Admin SDK or so).
What I have faced so far is this:
There are many related questions on SO, but most of them are outdated.
Java Quickstart for Google Directory API does not include an example using service accounts, and I want to use them because my app runs in a docker container, and using Oauth means I need to manually authorize it every time I deploy a new version or restart the container.
Google documentation makes reference to "API Reference" settings in Admin console, but I don't see that section there.
I am not storing credentials in a JSON file, I have them in an environment variable instead. I am doing this:
var inputStream = IOUtils.toInputStream(apiCredentials, Charset.defaultCharset()); //apiCredentials is a string with the JSON contents.
var credential = GoogleCredential
.fromStream(inputStream, httpTransport, JacksonFactory.getDefaultInstance())
.createScoped(Collections.singleton(DirectoryScopes.ADMIN_DIRECTORY_USER));
var directoryService = new Directory.Builder(httpTransport, JacksonFactory.getDefaultInstance(), credential)
.setApplicationName("My App")
.build();
var result = directoryService.users().list()
.setPageToken(pageToken)
.setDomain("my.domain")
.setMaxResults(10)
.execute();
After this, I get a 400 Bad request error, with no further description.
What am I doing wrong here?

Classroom API - Access classroom with Service Account

I need some help as I'm really stuck!!!! I have spent days and hours on this one but I can't figure it. I have searched all possible forums and other similar posts without any success.
So, the requirement :
We are trying to integrate Classroom API on our .Net platforms. The tricky part is that they want to use service accounts.
The problem :
Google.Apis.Requests.RequestError The caller does not have permission [403]
The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global]
I have followed the documentation as shown in :
https://developers.google.com/identity/protocols/OAuth2ServiceAccount.
I understand that we need to set up a service account in the Google API Console, so I've done the following:
1) I have created a service account and enabled G Suite Domain-wide Delegation in the Google API Console
2) In the Admin Console, in Manage API Client Access, I have entered the service account's client id and have enabled scopes.
3) A have downloaded the json file with all the service account credentials (private key, email)
and the code...
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(cr.client_email)
{
Scopes = new[] { ClassroomService.Scope.ClassroomCourses },
}.FromPrivateKey(cr.private_key));
// Create the service.
service = new ClassroomService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Demo-School",
});
and the actual call to the Classroom API to create a course :
var resource = service.Courses.Create(course);
var result = await resource.ExecuteAsync();
So, despite all that, whenever i try to create a course, I get the above error.
When I try to create a Course using the Reference page (https://developers.google.com/classroom/reference/rest/v1/courses/create) it works fine. I can create courses, teachers, set permissions etc..
But when I try to do that programmatically.. i.e from a console app, there is NO way I can get it working.
Can ANYONE please advice???????What am I missing??

Accessing google apis on behalf of google home user

I'm trying to develop a simple ProofOfConcept to interract with Google APIs from a Google Home using the authorization of the user through Dialogflow Fullfilment.
For example, we want to be able to create/read/update/delete contacts of users.
It's relatively easy to implement the Google SignIn but I don't know how to ask for additionnal scopes
Also, I never implemented an OAuth server before and I'm still not sure if I need too or if I could reuse en existing one.
I looked at many posts here on SO most of them was answered by #Prisoner who also provided a detailed flow in Google Home Authorization Code and Authentication with Google Account
In his answer, he mentions that we can "redirect the user to a web login page" but I still don't understand how to do that from the fullfilment
Here's the fullfilment code I used to use the Google SignIn:
//requirements
const { dialogflow, SignIn} = require('actions-on-google');
const functions = require('firebase-functions');
//initialisation
const app = dialogflow(
{
debug: true,
// REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT
clientId: '1111111111111-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.apps.googleusercontent.com'
});
//Welcome Intent
app.intent('Default Welcome Intent', (conv) => {
conv.ask(`Welcome to the demo agent, say "Connect-me" to proceed`);
});
//Default Intent
app.intent('Default Fallback Intent', (conv) => {
conv.ask(`Sorry, can you repeat please?`);
});
//Intent starting the Google SignIn
// Create an intent with the name "Start Signin"
app.intent('Start Signin', (conv) => {
//SignIn Helper (https://developers.google.com/actions/assistant/helpers#account_sign-in)
conv.ask(new SignIn(`Need to identify you`));
});
//Intent called when the user complete the authentication
// Create an intent with the name "Get Signin" and assign it the event "actions_intent_SIGN_IN"
app.intent('Get Signin', (conv, params, signin) => {
if (signin.status === 'OK') {
const payload = conv.user.profile.payload;
conv.ask(`Hello ${payload.name}. You can now access your contacts informations... but not really `);
} else {
conv.ask(`Sorry but you should authentify yourself `);
}
});
//Example of intent that I would like to make it works
app.intent('How many contacts', (conv) => {
/*
TODO: How to ask for additional scopes ("https://www.google.com/m8/feeds/" : read/write access to Contacts and Contact Groups)
NOTE: Actually, I'm more interrested on how to get the additional scopes.
I could probably do the querying contacts part by myself since it's quite documented (https://developers.google.com/contacts/v3/)
*/
conv.ask(new SignIn(`You have ${nbContacts} contacts defined in your Google Contact`));
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
You have a few related questions bundled here.
How do I ask for additional scopes with Google Sign In?
Unfortunately you can't.
This is for the user's security. Since it isn't always obvious when you're granting additional permissions via voice, and asking for too many scopes can be overwhelming with voice, they don't allow this right now.
Ok. So how do I get those additional scopes?
You referenced another post that goes through the method I propose to do that. It involves signing in and granting the scopes through a web page in the same Google Cloud Project. Under Google's cross-client identity system, these would then apply when the user connects through the Assistant as well.
So how do I direct them to a web page?
I typically either use a card with a link button for the website or a link out suggestion to the site. Both of these, however, depend on being on a visual interface that supports a web browser. So you might wish to check for this using surface capabilities.
If you are using your own OAuth server, using the combination "OAuth and Google Sign-In" method, the Assistant will take care of these sorts of things for you.
Do I need to write my own OAuth server?
No. You can use something like Auth0 to handle the OAuth part for you.

Oauth2 on Google Contacts API For DotNet - Token Invalid – AuthSub token has wrong scope

I have created a class that authorises a vb.net app to access Google Fusion Tables using Oauth2. It opens a web browser in a form if needed, encrypts and stores the refresh token, and it works well. I can access the fusion tables data.
However, I would also like to access Contacts. I have requested access to Contacts from the user.
I can retrieve the AccessToken that works for fusion tables and have tried different techniques to get things working on contacts, but no luck. I keep getting a 401-unauthorised error. But I can get Contacts working if I use clientlogin.
Any help would be much appreciated.
My latest try:
Dim rs As New RequestSettings("App Name", p.AccessToken) 'String retrieved from class
Dim cr As New ContactsRequest(rs)
Dim q As New FeedQuery
q.Uri = New Uri("http://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
Dim c As New Contact
c = cr.Retrieve(Of Contact)(q)
You have to request access to the Contacts API OAuth scope, which is https://www.google.com/m8/feeds/.
The .NET client library includes an OAuth 2.0 sample that uses the Contacts API:
https://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/samples/oauth2_sample/oauth2demo.cs
Thank you to Claudio Cherubino for the suggestion. I was actually already using that scope. Thankfully, I have now, finally, found the answer.
I was literally missing a single letter:
q.Uri = New Uri("http://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
... is wrong, as the scope I requested was indeed:
https://www.google.com/m8/feeds/
So the Uri needed to match, with httpS. I added the 's' and it works. Correct code below:
q.Uri = New Uri("https://www.google.com/m8/feeds/contacts/<EMAIL>/full/<IDCODE>")
Many thanks for this post for the answer:
http://www.geoffmcqueen.com/2010/03/14/token-invalid-authsub-token-has-wrong-scope-oauth-google-problem

Resources