Unauthorized client Google Calendar API (Google_Service_Exception) - unauthorized

I have setup Google calendar API project. I am using OAuth 2.0 to Access Google Calendar APIs data with consent screen.
I have followed the process mentioned here: https://developers.google.com/google-apps/calendar/quickstart/php
while I am trying to fetch all calendars for the authorized Google account. I am getting following error:
<h1>Google_Service_Exception</h1>
{
"error": "unauthorized_client",
"error_description": "Unauthorized"
}
Here is the code to fetch all calendars list:
$client = $this->getGoogleCalenderClient($clientSecretPath);
$accessToken = json_decode(file_get_contents($clientSecretPath), true);
$client->setAccessToken($accessToken);
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$result = $s3Client->putObject([
'Bucket' => $bucketName,
'Key' => $credentialsPath,
'Body' => json_encode($client->getAccessToken())
]);
}
$service = new Google_Service_Calendar($client);
$calendarList = $service->calendarList->listCalendarList();
Does anyone know what this is happening here? And how can I fix this error?
Grateful for any help.

Does anyone know what this is happening here? And how can I fix this error?
If you are accessing the application using service account,
check this Github and the official document of Google for domain-wide delegation.
The following steps must be performed by an administrator of the Google Apps domain:
Go to your Google Apps domain’s Admin console.
Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls. If you can't see the controls, make sure you're signed in as an administrator for the domain.
Select Advanced settings from the list of options.
Select Manage third party OAuth Client access in the Authentication section.
In the Client name field enter the service account's Client ID.
In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example, if your application needs domain-wide access to the Google Drive API and the Google Calendar API, enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar.
Click Authorize.

Related

Integrate AWS Cognito with Google Workspace using SAML integration

I have some applications served to my company users on EKS (i.e., Jenkins). In company we use Google Workspaces (GSuite) for email and stuff. So I want to allow users to login with Google creds to those applications I serve. I figured out I could use Cognito to achieve it but I cannot connect those and flow end with Google showing 403. Error: app_not_configured_for_user. In their documentation I can find:
Verify that the value in the saml:Issuer tag in the SAMLRequest matches the Entity ID value configured in the SAML Service Provider Details section in the Admin console. This value is case-sensitive.
but how do I debug it? I do not see a logs from neither AWS and Google sides :/
I think I followed all possible guides and I cannot find what I'm doing wrong. I found that Google has this page but they do not provide exact scenario for AWS Cognito. Anyways all of those are very similar so I guess I shouldn't have problems, but I do have.
What I did:
In Google Admin (one for workspaces) I created "Web and mobile app" of SAML type
I downloaded metadata file
In AWS Cognito console I created User Pool
I created IdP provider and uploaded metadata file there
I created application client
Using those values I filled fields ACS URL and Entity ID in Google Admin using values:
ACS URL: https://my-domain-i-just-created.auth.us-east-1.amazoncognito.com/saml2/idpresponse
Entity ID: urn:amazon:cognito:sp:us-east-1_myPoolId
I also selected Name ID format to be Persisted
In attribute mapping I mapped email value to http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress.
In AWS Cognito I enabled HostedUI and also created mapping of http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress to email field.
And now when I click View Hosted UI in AWS console it will redirect me to Google authentication and after it directly to before mentioned 403 app_not_configured_for_user page.
I tied it 3 times with slightly different configurations of mapping, signed responses, etc. but nothing gets me past that error.
Anyone tried to integrate it?
How to troubleshoot the 403 app_not_configured_for_user error related to SAML apps from the Google Workspace Admin console
The first thing you need to do is to grab a HAR file recording the whole login process and find the SAML request. Steps can be found here.
Once you get the file you can open it using that tool and search for SAMLreq at the top right (see image).
After that you will get a list of values containing information. You will have to check one by one until you find the one that has the SAML request in the request tab (see example below).
Once you get the value from the SAML request, copy it and you can use this tool to do a SAML decode and find the entity ID. You can use Ctrl + F and search for saml:Issuer to find the value faster. If the value does not match, then you know you have an error and you will need to contact the support team from the app to see which value is the correct one.
In case the value matches I would recommend opening a ticket to check with Google.

Google api credentials screen stuck spinning after adding a postman redirect URI

I have created a new project in Google cloud console to experiment with Google OAuth flows. I have therefore set up OAuth web app client credentials using
APIs & Services -> Credentials -> Create Credentials -> OAuth Client ID -> Web Application
I want to be able to experiment with postman to request authorisation codes, access/refresh tokens etc. Once in the Create OAuth client ID I therefore add a postman callback URI (https://oauth.pstmn.io/v1/callback) to the credentials' Authorised Redirect URIs as described here. However when I click CREATE at the bottom of the Create OAuth client ID screen, the screen does not update and just keeps spinning. I have waited for over 20 mins but to no avail. Is this a callback URI validation problem such that Google won't allow me to add this redirect URI to the credentials? I have tried to add the domain oauth.pstmn.io to the authorised domains in the project settings but to no avail. When I don't include the redirect URI, the credentials are created with no problem and I am returned to the main APIs & Services -> Credentials screen.
The user that I am using to make these changes owns the project and therefore I do not suspect it is a Google user permissions issue. I have also added the minimum number of fields (project name and support email) to the OAuth consent screen settings. I have also tried this whole process logged in on a different machine.
It seems that at least one api scope needs to be added to OAuth consent screen->Scopes before you set a redirect URI. This video explains the entire setup.
https://documenter.getpostman.com/view/8296678/TzXtGzS2
you can use this public collection to learn more about how to set up auth token for google APIs

Google sheets API v4 permissions PERMISSION_DENIED error using POSTMAN [duplicate]

I've generated a server key in the API Manager and attempted to execute the following on my Mac:
curl 'https://sheets.googleapis.com/v4/spreadsheets/MySheetID?ranges=A1:B5&key=TheServerKeyIGeneratedInAPIManager'
But this is what it returns:
{
"error": {
"code": 403,
"message": "The caller does not have permission",
"status": "PERMISSION_DENIED"
}
}
What am I doing wrong here?
To solve this issue, try to:
Create a service account: https://console.developers.google.com/iam-admin/serviceaccounts/
In options, create a key: this key is your usual client_secret.json - use it the same way
Make the role owner for the service account (Member name = service account ID = service account email ex: thomasapp#appname-201813.iam.gserviceaccount.com
Copy the email address of your service account = service account ID
Simply go in your browser to the Google sheet you want to interact with
Go to SHARE on the top right of your screen
Go to advanced settings and share it with an email address of your service account ex: thomasapp#appname-201813.iam.gserviceaccount.com
I know it is a little late to answer but for other people struggling with the same issue.
Just change the permission of the sheet to public on your drive so it can be accessed without authentication via API calls.
To change access:
Open sheet in google drive
On top right corner, click share
On bottom of prompt window, click advanced
Change permission to public or people with link (no signin required)
Send API request to fetch data from sheets without authentication.
Note: if the sheet contains sensitive data then it is not safe to make it public and rather do it with Authenticated access.
Make sure to pay attention to #KishanPatel's comment:
Also, you can share this sheet with specific email Ex. your service
account (project) email. "client_email":
"XXXXX#northern-gasket-XXXX.iam.gserviceaccount.com", This will allow
to access sheet by your script.
Visual Simplification of the Answers:
Option 1 - Turn the file into public (if sheets the sheet contains sensitive data)
Option 2 - Share file with Service Account Email (IAM & Admin -> Service Accounts -> Details -> Email)
The easiest way is to fix using gcloud cli. More docs here https://cloud.google.com/pubsub/docs/quickstart-cli#before-you-begin
install gcloud
sudo apt-get install google-cloud-sdk
then call
gcloud init
then check your active project and credentials
gcloud config configurations list
If it is not ok, make sure you are authenticated with the correct account:
gcloud auth list
* account 1
account 2
Change to the project's account if not:
gcloud config set account `ACCOUNT`
Depending on the account, the project list will be different:
gcloud projects list
- project 1
- project 2...
Switch to intended project:
gcloud config set project `PROJECT NAME`
Then Create Application Default Credentials with gcloud auth application-default login, and then google-cloud will automatically detect such credentials.
My 10 cents... A simple example to read the sheet using Java.
private Credential getCredentials() throws IOException {
final InputStream accessKey = new ByteArrayInputStream("<credential json>");
final GoogleCredential credential = GoogleCredential.fromStream(accessKey)
.createScoped(Collections.singleton(SheetsScopes.SPREADSHEETS_READONLY));
return credential;
}
private HttpTransport httpTransport() {
try {
return GoogleNetHttpTransport.newTrustedTransport();
} catch (GeneralSecurityException | IOException e) {
throw new SpreadSheetServiceException(e);
}
}
Sheets service = new Sheets.Builder(httpTransport(), JSON_FACTORY, getCredentials())
.setApplicationName("app-name")
.build();
ValueRange response = service.spreadsheets().values()
.get("<spread_sheet_id>", "A1:A")
.execute();
In my case, solving this problem turned out to be trivial. You just have to:
Enter the google sheet that we want to remotely edit.
In the upper right corner, set - anyone who has the link can enter
Most importantly - on the right side you need to set permissions for people who have the link as 'editor'
if you still do not have permission, it means that you have to go to the website:
https://console.developers.google.com/iam-admin/iam/ then select your project, then select "Service accounts" and create a new one as role "owner" or" editor" for the project for example (or use one that already exists and click "create new key")
The "key" is a json file that will be downloaded when you create the account (or use "create new key" there).

Accessing users account with service account

We need to use an API to verify if a certain user exists as managed account (it means, that belongs to our Google Domain organization).
GSuite adminSDK performs that operation, however, it requires OAuth2 authentication, authorized by an authenticated user - https://developers.google.com/admin-sdk/reports/v1/guides/authorizing .
My question is, if there any way to use that API with service account, or any other methos to retrieve this information with service account, since it would be used in a Server-2-Server scenario.
Thanks,
Vasco
As you may know, Service Accounts don't belong to an individual end user, but to an application. An administrator of a G Suite domain, though, can authorize the Service Account to access user data, that is, to impersonate users in the domain. This is called domain-wide delegation.
To achieve this, go to the Admin console and follow the steps specified here.
Reference:
Delegating domain-wide authority to the service account
Reports API > Perform G Suite Domain-Wide Delegation of Authority
Since this is completely not obvious - the docs "hint" at this, but don't spell it out and I had trouble finding any specific examples that worked. They all kept returning this error:
Google.GoogleApiException: 'Google.Apis.Requests.RequestError
Not Authorized to access this resource/api [403]
Errors [
Message[Not Authorized to access this resource/api] Location[ - ] Reason[forbidden] Domain[global]
]
The basic issue that the service account MUST impersonate another user. It's mentioned in this link at the bottom, highlighted in blue:
https://developers.google.com/admin-sdk/directory/v1/guides/delegation
Only users with access to the Admin APIs can access the Admin SDK Directory API, therefore your service account needs to impersonate one of those users to access the Admin SDK Directory API. Additionally, the user must have logged in at least once and accepted the Google Workspace Terms of Service.
But it just wasn't clicking as to how I was supposed to do that - was this some setting hiding in one of the admin consoles? No - you pass this as part of your initial connection.
So just to put the instructions in one place and hopefully save someone else the same headache, these were the steps:
Created a project via https://console.developers.google.com
Searched for then enabled the Admin SDK API
Created a Service Account
Show domain-wide delegation / Enable G Suite Domain-wide Delegation
At this point I had a service account name, unique ID, Email, and Client ID
It generated a key file (json) that I downloaded.
Go to: https://admin.google.com
Security > API Controls.
Manage Domain Wide Delegation
Added entry using client ID from above, applied these two scopes - you can apply other scopes as needed.
https://www.googleapis.com/auth/admin.directory.user.readonly
https://www.googleapis.com/auth/admin.directory.group.member.readonly
Then I created a .NET Core console app and installed these NuGet packages:
Google.Apis
Google.Apis.Auth
Google.Apis.Admin.Directory.directory_v1
Here's an ugly proof of concept with everything working:
using System;
using System.IO;
using System.Net;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
namespace GoogleDirectoryTest
{
class Program
{
static void Main(string[] args)
{
var dirService = GetDirectoryService(#"C:\tmp\google-cred-sample-12345abdef.json", "user-with-admin-permission-here#mydomainhere.com", "My App Name");
var list = dirService.Users.List();
list.Domain = "mydomainhere.com";
var users = list.Execute();
foreach (var user in users.UsersValue)
{
Console.WriteLine($"{user.Name.FullName}");
}
Console.ReadKey();
}
static DirectoryService GetDirectoryService(string keyfilepath, string impersonateAccount, string appName)
{
using (var stream = new FileStream(keyfilepath, FileMode.Open, FileAccess.Read))
{
var credentials = GoogleCredential.FromStream(stream).CreateWithUser(impersonateAccount);
if (credentials.IsCreateScopedRequired)
credentials = credentials.CreateScoped(new[] { DirectoryService.Scope.AdminDirectoryUserReadonly });
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = appName,
});
return service;
}
}
Hopefully this saves someone else some headaches.
A service account is a special kind of account used by an application, rather than a person.
You can use a service account to access data or perform actions by the robot account itself, or to access data on behalf of Google Workspace or Cloud Identity users.
Prerequisites:
A Google Cloud Platform project
With the Admin SDK API enabled service account with domain-wide delegation.
A Google Workspace domain.
With account in that domain with administrator privileges.
Visual Studio 2013 or later
Step 1: Set up the Google Cloud Platform project
Create Google Cloud project
A Google Cloud project is required to use Google Workspace APIs and build Google Workspace add-ons or apps.
If you don't already have a Google Cloud project, refer to: How to create a Google Cloud project
Enable Google Workspace APIs
Before using Google APIs, you need to enable them in a Google Cloud project.
To Enable Google Workspace APIs refer to: How to Enable Google Workspace APIs
For this example you are enabling the the Admin SDK Directory API
with the data scope /auth/admin.directory.user.readonly.
Create Service Account with domain-wide delegation
To create service account refer to: How to create service account?
In the Domain wide delegation pane, select Manage Domain Wide Delegation.
Download Service Account private key (p12 format)
Download p12 file contains the private key for your Service Account.
Step 2: Set up the Google Workspace
Enable API access in the Google Workspace domain with
To enable API access in Google Workspace domain, refer to: how to enable API access
Delegating domain-wide authority to the service account
To call APIs on behalf of users in a Google Workspace organization, your service account needs to be granted domain-wide delegation of authority in the Google Workspace Admin console by a super administrator account
To delegating domain-wide authority in Google Workspace domain, refer to: How to Delegating domain-wide authority to the service account
Step 3: Prepare Visual Stodio project -
Create a new Visual C# Console Application (.NET Framework) project in Visual Studio.
Open the NuGet Package Manager Console, select the package source nuget.org, and run the following commands:
Install-Package Google.Apis.Auth
Install-Package Google.Apis.Admin.Directory.directory_v1
Step 4: Add code
Full example at GitHub
List top 10 users alias from Google Workspace Domain
/// <summary>
/// Example how to list all users from google workspace domain, using a service account (user impersonation).
/// </summary>
internal class Program {
static void Main(string[] args) {
// Scope for only retrieving users or user aliases.
string[] _scopes = {
"https://www.googleapis.com/auth/admin.directory.user.readonly"
};
var _paramters = new SACInitializeParameters(
// The service account ID (typically an e-mail address like: *#*iam.gserviceaccount.com)
serviceAccountId: "[Service Account ID]",
// The full path; name of a certificate file
x509CertificateFilePath: "[X509 Certificate File]",
// The email address of the user you trying to impersonate
impersonateEmail: "[User Email]",
// The scopes which indicate API access your application is requesting
scopes: _scopes);
using (var directoryService = DirectoryServiceFactory.CreateDirectoryService(_paramters)) {
// Retrieves a paginated list of either deleted users or all users in a domain.
var request = directoryService.Users.List();
// The unique ID for the customer's Google Workspace account
// the `my_customer` alias represent current identety account's
request.Customer = "my_customer";
request.MaxResults = 10;
var response = request.Execute();
foreach (var user in response.UsersValue) {
System.Console.WriteLine($"{user.Name.FullName}, {user.PrimaryEmail}, {user.Id}");
}
}
}
}

Google Directory API users list gives 404 Not found

I'm using the javascript client library to try to get a list of users in a domain, but I'm getting a 404 not found in the response.
gapi.client.load('admin', 'directory_v1', function() {
var request = gapi.client.directory.users.list({ domain: "mydomain.com"});
request.execute(function(resp) {
console.log(resp);
});
});
I have a load function before this that gets the userinfo and that works fine, it's just the directory api I can't get working. I added the admin.directory.user scope, and I have the proper client id and api key. I enabled the Admin SDK in the Services tab of my project. The account that the project was created in has all administrator privileges except super admin. Is there some extra step you have to take to use admin sdk apis? What am I missing?
Any help would be appreciated.
You need to grant Oauth access for ClientId in admin console.
Security -> Advanced settings -> Manage Oauth client access
And then add your client ID and the scope needed.