Google Drive API "commenter" permission fails but all others work - ruby

I'm unable to share a folder on the Google Drive API with the commenter permission using the Google API client gem. I've tried making the same CREATE manually in Postman and I have the same issue. I've confirmed that my access token, user email and folder_id are all valid.
drive = Google::Apis::DriveV3::DriveService.new
drive.authorization = get_access_token
role = "commenter"
perm = Google::Apis::DriveV3::Permission.new(type: "user", role: role, email_address: email)
drive.create_permission(folder_id, permission_object = perm, email_message: "You've been invited to work on a folder.")
Response:
400 Bad Request. User message: "Sorry, an item is restricted in sharing."

I tried to accomplish your goals, but I wasn't able to. After different scenarios and set-ups I ended up with the Sorry, an item is restricted in sharing. 400 error. As a result, I reported this behaviour to Google and an IssueTracker was made out of it. You could go and click on +1 to make this issue more popular.

Related

How do i access my youtube brand account api? [duplicate]

I need to extract information from videos using YouTube Analytics and Reporting Api.
I have access to multiple YouTube Brand Accounts, when I log into YouTube with my Google Account.
Using the "Try it" for testing the API, I'm only able to retrieve data for a channel once I switch to the Brand Account that this channel belongs, otherwise I get 403 - Forbidden error.
Is there any way to extract data using the Google Account that I'm using to log in? Because once I create the credentials in developers console, they will be associated to the Google Account and not to the Brand Accounts.
My google account has Manager Role on the brand accounts.
I've search for the onBehalfOfContentOwner field to be used in requests, but I don't know how to get this ID, and I'm not sure if this is applicable in my situations, since we're talking about Brand Accounts, correct me if I'm wrong.
I fought with this just two days ago. Turns out it IS possible, it's just undocumented and works a bit differently than you'd expect:
Once I create the credentials in developers console, they will be associated to the Google Account and not to the Brand Accounts.
I had the same exact misconception when I first tried (even went so far as to find out the brand account's client_id). Turns out you don't want to use the brand's oauth info -- you want to use your own client_id/client_secret to create a refresh token on behalf of the brand account then use that to create auth tokens.
Steps:
Using your main account create an oauth client_id and client_secret via https://console.developers.google.com/apis/credentials
Edit the client_id/client_secret entry you just added and add "https://developers.google.com/oauthplayground" to the "Authorized redirect URIs" at the bottom of the page.
We're going to create a refresh token the lazy way. Go to https://developers.google.com/oauthplayground/
Click the gears on the top right corner and set access type to "offline", then click "Use your own OAuth credentials" and enter the client_id and client_secret you created in step 1.
Select the scopes you want to give it access to. Click authorize APIs.
Here's the magic bit: You'll now be asked to "Choose an account". Choose the brand account you want to access here, NOT your main account. Since you have permission to access it this'll work fine even though you're using your own client_id and client_secret
Allow the permission access when it prompts you, then you'll be brought back to the oauth playground.
Click "Exchange authorization code for tokens"
Grab the refresh token and use it like normal to generate auth tokens as needed.
Congratulations, you now have api access to the brand account!
Hope that helps.
The YouTube API is different then other google APIs. With other APIs you authenticate access to the full account. However with the YouTube API its channel based. You are going to need to authenticate your application once for each channel.
onBehalfOfContentOwner
This parameter is intended for YouTube content partners that own and
manage many different YouTube channels. It allows content owners to
authenticate once and get access to all their video and channel data,
without having to provide authentication credentials for each
individual channel. The actual CMS account that the user authenticates
with needs to be linked to the specified YouTube content owner.
You need to be a YouTube partner then you can contact your account manager and get a CMS id. I have yet to figure out what magic one must archive to become a YouTube partner.
I will give an update to #Paolo's incredible answer. In my case, I was trying to get my private videos using the Playlist.list api. I've never seen an api as poorly documented, asinine, and CONVOLUTED as youtube's api.
Context: I have a main google account for which my youtube api credentials are tied to (there is no google developer accounts for youtube brand accounts) but would like to get the private playlists (and videos) for my youtube account (a brand account). mine=true, key, channelId, onBehalfOfContentOwner, and onBehalfOfContentOwnerChannel all did NOTHING for me. I was getting either public playlists or api errors with various combinations and values of those parameters.
In the end, these were the steps I took to run a node script to get private videos from my brand account:
Go to https://console.developers.google.com/ for your main google account.
In the sidebar, go to APIs & Services, then Credentials
At the top, click +Create Credentials, then Service account
Under Service account details, enter any name, then click Create and Continue
Under "Grand this service account access to project", click continue
Under "Grant users access to this service account", click Done
On the main credentials page that loads, click the newly created service account under Service Accounts
In the tabs, click Keys
Click the Add Key button, then Create new key
Keep JSON, then click create
Save the file as client-key.json in the root of your nodejs project
Go to https://developers.google.com/oauthplayground
Scroll to bottom of scopes and select YouTube Data API v3 v3, then https://www.googleapis.com/auth/youtube and https://www.googleapis.com/auth/youtube.readonly.
In the window that pops up, click your youtube (brand) account, then allow
In the next step, click Exchange authorization code for tokens
Copy the access token
Go back to your node script and use like this:
const auth = new google.auth.GoogleAuth({
keyFile: "client-key.json",
scopes: [
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.force-ssl",
"https://www.googleapis.com/auth/youtube.readonly",
"https://www.googleapis.com/auth/youtubepartner",
"https://www.googleapis.com/auth/youtubepartner-channel-audit",
],
})
const authClient = await auth.getClient()
google.options({ auth: authClient })
const youtube = google.youtube("v3")
const token = "your token here"
const results = await youtube.playlists.list({
part: [
"snippet",
"id",
"contentDetails",
"status",
"localizations",
"status",
],
mine: true,
auth: token,
oauth_token: token,
maxResults: 50,
})
Note mine: true and that the token must be passed to BOTH auth and oauth_token, but not key. If either parameter is missing, the call will fail. (Why? No clue. Please tell me.) Also, you must continuously renew your access token in the playground after it expires.
Now, with all of this said, I encourage you to find me an api worse than the youtube api. My guess is you'll be hard-pressed to find one even half as ridiculous as this.
P.S.
I believe there were additional things required before this such as enabling the youtube api and doing something on the OAUTH Consent Screen but I'm too exhausted with this thing to continue. Hopefully the Google console UX will be enough to guide you through those steps, though quite frankly, I doubt it.
Hope this helps and good luck, because you may actually need it.
If you follow the solution for getting a permanent refresh token and use Java, this works for me
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setClientSecrets(oauth2ClientId, oauth2ClientSecret)
.build()
.setRefreshToken(oauth2RefreshToken);
this.youTubeClient = new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME)
.build();
Required dependencies
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId>
<version>v3-rev212-1.25.0</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.18.0</version>
</dependency>
These resources might also help once you have the refresh token:
Authenticate programmatically to Google with OAuth2
https://blog.timekit.io/google-oauth-invalid-grant-nightmare-and-how-to-fix-it-9f4efaf1da35

Need to know what some google permissions mean

I was a victim of yesterday's google doc phishing attack. The email I received had a link and when clicked it asked for certain permissions. I gave access at that time but after few minutes I removed the permission from my google security page. However I am not sure what kind of permissions were given to the hacker. If I click on the link now the google page shows this message.
Error: disabled_client
The OAuth client was disabled.
Request Details
client_id=946634442539-bpj9bmemdvoedu8d3or6c69am3mi71dh.apps.googleusercontent.com
scope=https://mail.google.com/ https://www.googleapis.com/auth/contacts
immediate=false
include_granted_scopes=true
response_type=token
redirect_uri=https://googledocs.gdocs.pro/g.php
customparam=customparam
That’s all we know.
What kind of permissions were given to the hacker based on the above information? I am more interested in whether the hacker had access to my emails or not.
If they were able to gain access to my emails, is there a way to check whether or not they were able to successfully download my emails? I had removed the permission few minutes after giving access.
The hacker had access to your contacts and your mail account, as visible in this line:
scope=https://mail.google.com/
https://www.googleapis.com/auth/contacts

HttpError 403 google directory api

I got the super admin privileges for to my Google Account.
I need to get the list of all the chrome devices through an API.
I did enable Google Admin SDK but still facing some issues.
I copied the exact python script from Python Quickstart for checking but still getting error as
"googleapiclient.errors.HttpError: https://www.googleapis.com/admin/directory/v1/users?customer=my_customer&orderBy=email&alt=json&maxResults=10 returned "Insufficient Permission">"
When checked on Admin SDK API dashboard I can see 4xx errors for every call made from my python script.
When you run the sample you need to make sure that this step
The sample will attempt to open a new window or tab in your default browser. If this fails, copy the URL from the console and manually open it in your browser.
If you are not already logged into your Google account, you will be prompted to log in. If you are logged into multiple Google accounts, you will be asked to select one account to use for the authorization.
Is done from the Google account which has access to your admin account. The user you are logged in with now does not have access.
I managed to get Super Admin access of Google account and then grant access to my project for different scopes. The docs/ references are so confusing hence it took a while for me to figure it out. So under the admin console, we have to get into Security >> Advanced Settings >> Manage API Client Access(under Authentication) and then add the client name and the scopes(multiple scopes separated by commas) for which we need access. Client name is the client-id which we can get from the client-secretxxxxx.json file(downloaded while creating the oauth id).
NOTE :- You do NOT need super admin access it is just that I was new and the guy who gave me the initial access wasn't sure what has to be enabled across.
Also couldn't post as a comment due to the limitation of characters.

Google+ Domains API via service account fails with 403 Forbidden

I have a simple Ruby code that I combined from several examples. It uses Google+ Domain API. I followed all steps to authorize a service account (https://developers.google.com/+/domains/authentication/delegation), but my requests fail with 403 Forbidden:
{"error"=>{"errors"=>[
{"domain"=>"global", "reason"=>"forbidden", "message"=>"Forbidden"}],
"code"=>403, "message"=>"Forbidden"}}
The same queries work fine if I execute them using Google APIs Explorer console. I think it's related to the service account vs. user account authentication. What did I miss?
The full code is here https://github.com/admitriyev/propellant/blob/master/main.rb
[edited] I added an installed app flow into the same code, and it worked fine (full code is on Gihub above). I still don't know what I missed in the service flow though.
I figured it out, I was missing the email of the actual domain user on behalf of whom it should be authorized. I also switched to use Google::APIClient::JWTAsserter which is a cleaner
abstraction:
client_asserter = Google::APIClient::JWTAsserter.new(
config['client_email'],
PLUS_LOGIN_SCOPE,
key
)
$client.authorization = client_asserter.authorize(config['user_email'])
My full example is here: https://github.com/admitriyev/propellant/blob/master/main.rb

Google OAuth2 re-authorization is missing permissions on the consent page

When I force a user to re-authorize my application a second time, using approval_prompt=force, how can I get Google to show the user the entire list of permissions my app is requesting?
Details:
I have a web application that requests a set of Google API permissions, including access_type=offline. The first time I approve it, it shows the correct consent page, listing all the permissions, which looks like:
Later, I send the user back to authorize with Google, with the same parameters. The second time, it only shows "Have offline access":
Why does it not show the users all the permissions? Is there a way to force it to ask the user for all the permissions a second time? Why does it now show "Have offline access" the first time?
Our users find it confusing that our app is not asking for any actual permissions, so I'd rather just show the first approval screen again.
The full parameters for the request I am making are as follows. URL:
https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=1039955146864.apps.googleusercontent.com&redirect_uri=http://localhost:8081/sync/google/callback&response_type=code&scope=openid%20email%20https://www.googleapis.com/auth/admin.directory.group.readonly%20https://www.googleapis.com/auth/admin.directory.group.member.readonly%20https://www.googleapis.com/auth/admin.directory.user.readonly&state=480704597031619284232891277399900450622
Parameters broken out:
access_type:offline
approval_prompt:force
client_id:1039955146864.apps.googleusercontent.com
redirect_uri:http://localhost:8081/sync/google/callback
response_type:code
scope:openid email https://www.googleapis.com/auth/admin.directory.group.readonly https://www.googleapis.com/auth/admin.directory.group.member.readonly https://www.googleapis.com/auth/admin.directory.user.readonly
state:480704597031619284232891277399900450622
We launched incremental auth and this is the working as designed.
http://googleplusplatform.blogspot.com/2013/12/google-sign-in-improvements11.html
The idea is if a user has already granted the permissions to an app, there is no need to show the same permissions and ask the user to approve.
If you write your application properly then this situation should not arise. If you request an offline code (refresh token) and store it on your backend, you shouldn't be asking for it again unless if you need to get some new scopes/permissions. You should use the refresh token that you have stored in the future. If you only need the access token when the user is on your site, you can use other flows to request an access token without user seeing an approval page.
You have to revoke the access token and log out. Then if you go to sign in process, It will show the permission.
public static void RevokeAcess(String accessOrRefreshToken) throws ClientProtocolException, IOException
{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/revoke?token="+accessOrRefreshToken);
client.execute(post);
}
This network process should be called in non ui thread or asyntask

Resources