Access google connections using google people API - google-api

I would like to fetch all the google private connections of a user signed in from my app.
I've enabled the Google People and the Google Plus API's. I set up the credentials API key, client id & client secret. The url with which I'm trying to fetch the users connections is
https://people.googleapis.com/v1/people/me/connections?fields=connections&key=api_key&access_token=access_token
Also, I'm using the library passport-google-oauth, to get the users access_token. Is there anything that I'm missing in the above URL.
My google auth code is
// send to google to do the authentication
// profile gets us their basic information including their name
// email gets their emails
app.get('/auth/google', passport.authenticate('google', {
scope: ['profile', 'email','https://www.googleapis.com/auth/contacts.readonly', 'https://www.googleapis.com/auth/contacts']
}));
// the callback after google has authenticated the user
app.get('/auth/google/callback',
passport.authenticate('google', {
successRedirect: '/profile',
failureRedirect: '/'
}));

You have not mentioned what error you are getting but by looking at the url you are using I can tell you a few things.
people.connections.list access private user data. So for one you don't need to add Key that is just used for accessing public data. However having both should not result in any error message.
I have tested the request you are sending and it does work however this request requires that you have authenticated with at least one of the connections scopes.
https://www.googleapis.com/auth/contacts Requests that your app be
given read and write access to the contacts in the authenticated
user’s Google Contacts.
https://www.googleapis.com/auth/contacts.readonly Requests that your
app be given read access to the contacts in the authenticated user’s
Google Contacts.
If you have not then you will get a no access error message.
{
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED"
}
}

Related

ACCESS_TOKEN_SCOPE_INSUFFICIENT when trying to access Google Classroom course announcements

My user account can use the Google Classroom web UI to see all the announcements for a given course. Trying to pull them programmatically using the Google Classroom API.
I've set up an app with Oauth consent screen covering (for test purposes) ALL the scopes listed under the Google Classroom API, and can run the consent flow with my user account to get an access token.
I can successfully GET course details by curl'ing https://classroom.googleapis.com/v1/courses/<my course ID> using the access token obtained from the oauth flow. However, when I GET https://classroom.googleapis.com/v1/courses/<my course ID>/announcements with the same token, I get the following:
{
"error": {
"code": 403,
"message": "Request had insufficient authentication scopes.",
"status": "PERMISSION_DENIED",
"details": [
{
"#type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT",
"domain": "googleapis.com",
"metadata": {
"method": "google.classroom.v1.Work.ListAnnouncements",
"service": "classroom.googleapis.com"
}
}
]
}
}
Behaviour is same in using both client libraries as well as raw REST calls.
Am I missing an auth scope (I switched them all on), am I just not allowed to do this since I'm not the course owner, or am I doing something else wrong? Advice please!
You apear to be using the courses.get method
In order to access this method your application needs to be authorized with one of the following scopes.
You also appear to be using the courses.announcements.list method
This method requires that your application be authorized with one of the following scopes.
The error message "Request had insufficient authentication scopes." means exactly what it says. The access token you are using was not authorized with one of the scopes needed for the courses.announcements.list endpoint there for you can not use it.
You need to delete the access token you have now and request authorization of the user using the proper scope for this method. Always make sure to delete your old token. When changing scopes in code your app does not always request authorization again if you just change the scopes in the code. You need to force it to request authorization again.
All the scopes
you should not be requesting all of the scopes of the user only the scopes that you need. If you only need readonly access make sure not to request write.
I had forgotten that my code explicitly defines the scopes when configuring the client that then builds the oauth request URL:
config, err = google.ConfigFromJSON(b, classroom.ClassroomCoursesReadonlyScope)
Changed to
config, err = google.ConfigFromJSON(b, classroom.ClassroomCoursesReadonlyScope, **classroom.ClassroomAnnouncementsReadonlyScope**)
and it works fine.

How to authorise a service account to access the Google Admin API

We are trying to create an integration with the Google Admin SDK in order to be able to retrieve, update and create accounts within our domain. However, we keep receiving a 403 error indicating that we are not authorized to access the resource/api.
We are using the credentials obtained from a service account which has Domain-wide Delegation of Authority enabled and the following two scopes:
https://www.googleapis.com/auth/admin.directory.user.readonly, https://www.googleapis.com/auth/admin.directory.user. We are generating the JWT (which also includes these two scopes) and then sending a request to https://www.googleapis.com/oauth2/v4/token to retrieve the access token.
We are then using the access token to send a request to https://www.googleapis.com/admin/directory/v1/users?domain=XXXX.com. We are including the access token as a Bearer token, part of the headers.
In the response we are getting the following message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Not Authorized to access this resource/api"
}
],
"code": 403,
"message": "Not Authorized to access this resource/api"
}
}
Is it possible to clarify what are we doing incorrectly?
The problem was that the JWT must include the sub field: The email address of the user for which the application is requesting delegated access.
In order for this to work you must set up domain wide delegation by doing this your service account will then have access to the data in question.
Locate the newly-created service account in the table. Under Actions, click more_vert then Edit.
In the service account details, click expand_more Show domain-wide delegation, then ensure the Enable G Suite Domain-wide Delegation checkbox is checked.
If you haven't yet configured your app's OAuth consent screen, you must do so before you can enable domain-wide delegation. Follow the on-screen instructions to configure the OAuth consent screen, then repeat the above steps and re-check the checkbox.
Click Save to update the service account, and return to the table of service accounts. A new column, Domain-wide delegation, can be seen. Click View Client ID, to obtain and make a note of the client ID.

Google API 'Purchases.products: get' return 401 ERROR all of a sudden

Purchases.products: get had been working well till 2 weeks ago. However, it starts returning Error suddenly. (I didn't change any options)
It can still refresh token through POST request to https://accounts.google.com/o/oauth2/token with (grant_type, client_id, client_secret, refresh_token) but with the access-token returned, 403 Error happen like the below.
{
"error": {
"errors": [
{
"domain": "androidpublisher",
"reason": "permissionDenied",
"message": "The current user has insufficient permissions to perform the requested operation."
}
],
"code": 401,
"message": "The current user has insufficient permissions to perform the requested operation."
}
}
This is google dashboard representing error rate for Purchases.products: get
I found the question but it is still not working.
---------- EDIT ----------
I want to describe more detail. I don't know if it is right way because I am actually just fixing Legacy system someone did.
The process above(refreshing token and requesting purchase info) is done in server-side. It is for server-side to verify if the purchase-information APP send is correct.
When APP send purchase-information, server-side just call HTTP request(POST and GET) with pre-defined attributes(client_id, client_secret, grant_type).
It means there is no login process anywhere.
In addition, the client_id and client_secret I use seemed created in google-developer-console by create-credentials in below image but not when registering APP.
---------- Edit ----------
I tried to recreate client_id with an owner account. the screenshot is from google developer console->IAM&Admin->IAM
However, it is still the same error.
"The current user has insufficient permissions to perform the requested operation."
The user you have currently authenticated with no longer has access to the data you are trying to access. Either give the user access again or login with a user that does have access.
ClientId
When you wish to work with a Google API you must register your application. When you do so google gives you a client id. This identities your application to google when ever it runs.
Accessing User data
To access private user data you must have permission of the person who owns the data to access it. Your application runs (Denoted by the Client id) the user is prompted to login to google and grant your application consent to access their data.
If the user looses access to the data that they have granted your application access to your application will loose its access.

keyInvalid Error when calling Google Calendar API

I'm writing a Lambda function that queries Google Calendar events. Although I successfully created a credential (client ID, and client secret) on Google Developers Console, I cannot access the events. Error:
{ "error": { "errors": [{ "domain": "usageLimits", "reason": "keyInvalid", "message": "Bad Request" } ], "code": 400, "message": "Bad Request" } }
My http request looks like this:
https://www.googleapis.com/calendar/v3/calendars/MY_CLIENT_ID/events?key=MY_CLIENT_SECRET
What went wrong? Any help is greatly appreciated.
"domain": "usageLimits", "reason": "keyInvalid", "message": "Bad Request"
Means that the key you are sending is an invalid api key.
Background info
When you make a request to a Google api for public data you can use an API key. Public data is data that is not owned by a user. For example public posts on google+, google books. In these instances you can use an api key inorder to access the api using
GET https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=25&q=surfing&type=test&key={YOUR_API_KEY}
key identifies your application to google using the api key you create in google developer console.
Private data is data that is owned by a user for instance your google calendar an application can not post to it with out permissions. Inorder to do this we use Oauth2. You create a client on google developer console then login the user using oauth2. you will get an access token back then you can make a request
https://www.googleapis.com/calendar/v3/calendars/MY_CLIENT_ID/events?accesstoken=ACCESSTOKEN
Notice that the first request used key and the second used accesstoken.
Anwser
Your problem is that you are sending a client secret as an api key which will not work because first of all a client secret is not an api key and second events are private user data which will require that you authenticate your user first.

How to exchange Google one-time authorization code for a refresh token without callback (intranet)?

I'm working on a intranet-based application and I want to use Google services. Currently I have successfully implemented Google Authentication with "Sign-In for Websites" using JavaScript client-side authentication. My users can now sign in or sign up with their Google accounts.
Now I want to use Google API to create and share Google Sheets with my users. These documents will be created with a specific Google account and then shared with my users.
This is why I want to use this server-slide flow to get a one-time authorization code and exchange it for a refresh token:
https://developers.google.com/identity/sign-in/web/server-side-flow
This refresh token will be stored in my database allowing me to user Google services on behalf of this offline user.
Using JavaScript library, I was able to get the one-time authorization code that I send to my server with a AJAX request.
auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(grantOfflineAccessCallback);
var grantOfflineAccessCallback = function(authResult) {
var auth_code = authResult.code;
// Exchange the one-time authorization code for tokens
$.post(...);
}
On server-side I use Google API PHP Client (v2.0.0-RC6) to acquire an access and refresh token.
$this->client = new Google_Client();
$this->client->setClientId($this->clientId);
$this->client->setClientSecret($this->clientSecret);
$this->client->setAccessType('offline');
$this->client->setApprovalPrompt('force');
$response = $this->client->fetchAccessTokenWithAuthCode($oneTimeCode);
I wasn't able to exchange the authorization code.
Client error: `POST https://www.googleapis.com/oauth2/v4/token` resulted in a `400 Bad Request` response:
{
"error": "invalid_request",
"error_description": "Missing parameter: redirect_uri"
}
On this page we can read:
On the server, exchange the auth code for access and refresh tokens.
Use the access token to call Google APIs on behalf of the user.
On the JAVA example code:
REDIRECT_URI: // Specify the same redirect URI that you use with your web
// app. If you don't have a web version of your app, you can
// specify an empty string.
Because the application I working on is an intranet application, I tried to specify an empty string for this redirect_uri parameter before calling fetchAccessTokenWithAuthCode() method:
$this->client->setRedirectUri('');
... result in Redirect URI must be absolute.
Can we use this hybrid server-slide flow without callback URL?
Is there any solution to my problem?
Thanks,
Edit:
redirect_uri is where the user will be redirected to after he signed in. This URL must be registered in the Google Project (developers console). So redirect_uri is NOT the callback...!
Problem is now solved with:
$this->client->setRedirectUri('http://same.url.as.in.developers.console/');

Resources