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.
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
We have a webapp that integrates with a number of Google APIs (calendars, contacts, drive). We have an integrations panel where the user can selectively check on each integration. When a new integration is enabled we save the new refresh token Google returns and flag the old one as inactive. Great so far.
The problem is when we request a new scope (incremental), Google seems to correctly add the scope to the User (if we check granted scopes from the frontend it shows the correct list), but if we check scopes from the access token it will only list profile and whatever we just requested.
So if someone enables Calendar, that refresh token will have 'profile' and 'calendar', but if they then enable Drive, the new refresh token will have only 'profile' and 'drive', not 'calendar'. This is especially problematic for our Drive worker, as it will generate a lovely slew of errors as it tries to build out a User's Drive with a valid refresh token but invalid scopes.
On the backend, I'm using the setIncludeGrantedScopes(true) method before I cash in the code, and as far as I know the front end is doing what it should (it does seem to have the expected scopes), but the refresh token is not inclusive.
Tips/tricks/gotchas/etc?
So, it turns out that this was a fairly simple solution, but was documented in only one place: when the front-end requests an additional scope, it must also send up all current scopes.
Failing to do this will cause the returned refresh token to represent only the scopes included in the grant request, while the app will incrementally gain scopes as expected.
I am currently researching Google+ REST API to post to a user's stream.
The basic requirements are:
The post should be created without user's review using server side request (user should give his permission to post on his behalf in the future).
The post must be visible to all user's friends.
As i understand from reading the documentation, posting to the stream without actually getting permission in creation time from the user is impossible, however, creating 'moments' doesn't require permission upon-posting, so the user should give his permission when authorizing the app.
Since i didn't find anything that explains how can a moment be created to be visible to all user's friends - can someone who is familiar with this API explain how visibility of a moment is being determined and on which step? reference to an API documentation would be good as well, but i didn't find any.
Thanks
The moment methods do not write directly to a user's Google+ stream. They instead write to a user's profile, and are not necessarily viewable by others depending on the user's preferred sharing settings.
Manage app activities in Google
During authorization the user chooses who their activity is visible to.
Once authorized a user should be able to see their own activities on Google+ and you can view other people's activities by clicking on an app from their profile about page.
How do I lower the requested access level of an existing google project?
It's currently asking for:
View your email address
View your basic profile info
Manage your contacts
When all I really want is to authenticate a user for login purposes, and I think all I need for that is:
Have offline access
One of the parameters you are passing when you create a credential is called scope, and contains a list of each of the services your users must authorize.
From the OAuth 2.0 docs, scope contains a string or iterable of strings. Change it to the new scopes you want.