I want to access Google reseller api to get customers and subscriptions using google service account key but not able to do it. Below is my code snippet:
async function runSample() {
const auth = new google.auth.GoogleAuth({
keyFile: "../server/credentials/serviceAccountKey.json",
scopes: ["https://www.googleapis.com/auth/apps.order",
"https://www.googleapis.com/auth/apps.order.readonly"
],
});
// Acquire an auth client, and bind it to all future calls
const authClient = await auth.getClient();
google.options({ auth: authClient });
// Do the magic
const res = await reseller.subscriptions.list();
console.log(res.data);
}
runSample().catch(console.error);
Here I want to get list of the subscription from google reseller console. I referenced above code from google documentation. Here I am getting the error 'Authenticated user is not authorized to perform this action.' and reason given is 'Insufficient permissions'.
errors: [
{
message: 'Authenticated user is not authorized to perform this action.',
domain: 'global',
reason: 'insufficientPermissions'
}
]
If I try to access cloud channel service api I can using the same service account key but it is giving error for reseller api.
I have given service account the owner, cloud workstation admin and service account admin role access.
I have also added scopes in domain wide delegation(dwd).
What else permission do I need?
In order to use a service account it must first be configured though your google workspace account Create a service account
You must also denote in your code the name of the user who your service account has been configured to impersonate.
const auth = new google.auth.GoogleAuth({
keyFile: "../server/credentials/serviceAccountKey.json",
clientOptions: {
subject: 'user#yourdomain.com'
},
scopes: ["https://www.googleapis.com/auth/apps.order"
],
});
Related
I am working on Google Cloud Search API to search documents stored in Google Drive. I have Google Workspace account and few documents stored in Google Drive. I am able to search using Google Cloud search console but facing issue using below node.js code for searching using API.
Issue: I am able to generate the access token but get below error for search query:
Error: This project doesn't have Cloud Search's Query API Enabled,
and/or the Cloud Search Platform license has not been assigned to the
user account calling the Query API
var {google} = require("googleapis");
var serviceAccount = require('C:/nodejstest/key/serviceAccountKey.json');
// Specify the required scope.
var scopes = [
"https://www.googleapis.com/auth/cloud_search",
"https://www.googleapis.com/auth/cloud_search.query"
];
var jwtClient = new google.auth.JWT({
email: serviceAccount.client_email,
key: serviceAccount.private_key,
scopes: scopes,
subject: 'sample#example.com'
});
// Use the JWT client to generate an access token.
jwtClient.authorize(function(error, tokens) {
if (error) {
console.log("Error making request to generate access token:", error);
} else if (tokens.access_token === null) {
console.log("Provided service account does not have permission to generate access tokens");
} else {
var accessToken = tokens.access_token;
console.log('accessToken= ' + accessToken)
// Include the access token in the Authorization header.
}
});
const service = google.cloudsearch({version: 'v1'});
service.query.search({
auth: jwtClient,
requestBody: {
requestOptions: {
searchApplicationId: 'searchapplications/default',
debugOptions:{enableDebugging: true}
},
query: 'My query'
}
}).then((res) => {
console.log(JSON.stringify({results:res.results.length}));
console.log(JSON.stringify({resultsInfo:res.results[0]}));
}).catch((err) => {
console.error('Unexpected error with cloud search API.');
console.error(err.toString());
});
In above code I am passing workspace admins email id as subject.
I followed steps mentioned at below link
Configure access to the Google Cloud Search REST API
Perform Google Workspace domain-wide delegation of authority
Go to the google console then select the your project.
Then search for Cloud Search API then enable it.
Also make sure that your service account have access on Cloud Search Indexing API
I try to revoke the service account's token using POST https://oauth2.googleapis.com/revoke?token=ACCESS_TOKEN (documentation)
but it says,
{ "error": "invalid_request", "error_description": "Token is not revocable." }
Also tried GET https://accounts.google.com/o/oauth2/revoke?token=ONLINE_ACCESS_TOKEN and this gives the same error message.
I used the below function to acquire an access token of the service account.
function getAccessToken() {
return new Promise(function(resolve, reject) {
const key = require('../placeholders/service-account.json');
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
Revoke only works on Oauth2 credentials. When a user authenticates your application they grant your application access to their data. By revoking that access you remove that grant.
Service accounts are preauthorized manually. You would need to remove that authorization from what ever api the service account was authorized for.
I created a simple PowerApps Component Framework using the pac pcf init command.
After successfully packaging and importing this skeleton PCF application to my demo tenant I tried to add MSAL authentication to it.
I used the #azure/msal npm package to write a typescript configuration and login without adding React or Angular npm packages. I only used #azure/msal and package added during the pcf create process.
The final goal was to use the token received from the msal authentication make a request on a authorized method in my Wep Api.
The problem is that my Web Api is not located in my demo tenant and the user that is used for msal authentication is from the demo tenant and does not exist on the tenant of my Web Api.
I cannot change the login user in the popup window as it only displays the error message, and the guest user that was added to the demo tenant, that has access to the Web API cannot have Certificates added to it through portal azure or portal office admin center pages.
This is my login configuration(I will omit the tenant names and client id for the work tenant):
import { AuthenticationParameters, Configuration, UserAgentApplication } from '#azure/msal';
import { AuthOptions, CacheOptions, FrameworkOptions } from "#azure/msal/lib-commonjs/Configuration";
public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container:HTMLDivElement)
{
// Add control initialization code
const auth: AuthOptions = {
clientId:'clientid',
authority:'https://login.microsoftonline.com/tenantid',
redirectUri:'redirect uri',
validateAuthority: true
};
const cache: CacheOptions = {
cacheLocation:"localStorage"
};
const framework: FrameworkOptions = {
protectedResourceMap: new Map([
['web api url',['https://tenantid/clientid/uniquename (scope)']],
['CRM work sandbox',['CRM work sandbox user impersonation permission(scope)']]
]),
unprotectedResources:[]
};
const config: Configuration = {
auth: auth,
cache: cache,
framework: framework
};
const params: AuthenticationParameters = {
authority: 'https://login.microsoftonline.com/tenantid',
scopes:['offline_access',
'https://tenantid/clientid/uniquename(scope)',
'CRM work sandbox user impersonation permission(scope)'],
redirectUri:'web api redirect uri'
};
const userAgentApplication = new UserAgentApplication(config);
const login = userAgentApplication.loginPopup(params).then(data => {
console.log(data);
let user = userAgentApplication.getAccount();
console.log(user);
if (user) {
// signin successful
console.log('success');
} else {
// signin failure
console.log('fail');
}
}, function (error: string) {
// handle error
console.log('Error' + error);
});
}
The error message displayed:
AADSTS50177: User account 'user name' from identity provider
'https://sts.windows.net/guid/' does not exist in tenant 'name'
and cannot access the application 'client id'(name of registered
app in portal azure) in that tenant. The account needs to be
added as an external user in the tenant first. Sign out and
sign in again with a different Azure Active Directory user account.
Is there a way to test this without adding the pcf or account in my work tenant ?
const { google } = require('googleapis')
const privatekey = require('./a.json')
const scopes = ['https://www.googleapis.com/auth/chat.bot'];
const a = async () => {
try {
const jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
scopes,
'adminEmail#org.com'
);
await jwtClient.authorize();
const chat = google.chat({ version: 'v1', auth: jwtClient });
const res = await chat.spaces.messages.get({name:'spaces/XXX/messages/XX.XX'})
console.log(res)
}
catch(e) {
console.log(e)
}
}
a()
Error: Request contains an invalid argument
I am unable to find the invalid argument
Thanks in advance
Many Hangouts API request require the usage of a service account
You can consult in the documentation which type of requests are affected
For the requests requiring the usage of a service account - it is meant that the service account acts on its own behalf
Impersonation means that the service account acts on behalf of another user
Thus, impersonation is not allowed for requests that need to be carried out by a service account
Also mind that https://www.googleapis.com/auth/chat.bot is the scope to be used by the service account without domain-wide delegation
Users or impersonated service accounts need to use the scope https://www.googleapis.com/auth/chat instead - see also here
Last but not least, chat bots are not allowed to delete messages of other users
I am still struggling with Google's terminology of apis and services but my goal is to have automated functions via aws lambda which act on a G Suite Account (domain?) or more specific on users of this domain.
For now I just want to list all users of that domain. I run this code locally for testing.
What I have done:
I created a service account
I downloaded the json key file which contains the private key, private key id and so on
I enabled G Suite Domain-wide Delegation.
I delegated domain-wide authority to the service account from the GSuite Account
I added the following scopes for the client in the GSuite Admin Console:
https://www.googleapis.com/auth/admin.directory.group
https://www.googleapis.com/auth/admin.directory.user
This is the implementation:
const { google } = require("googleapis");
const auth = new google.auth.GoogleAuth({
keyFile: "credentials.json",
scopes:
"https://www.googleapis.com/auth/drive.readonly,https://www.googleapis.com/admin/directory/v1, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.directory.user",
});
const service = google.admin({ version: "directory_v1", auth });
service.users.list(
{
domain: "my.domain.com",
maxResults: 10,
orderBy: "email",
},
(err, res) => {
if (err) return console.error("The API returned an error:", err.message);
const users = res.data.users;
if (users.length) {
console.log("Users:");
users.forEach((user) => {
console.log(`${user.primaryEmail} (${user.name.fullName})`);
});
} else {
console.log("No users found.");
}
}
);
I am not sure why I have to add the scopes in the GoogleAuth object but I took this from the google documentation.
When I run this I get the following error:
The API returned an error: invalid_scope: Invalid OAuth scope or ID token audience provided.
The Directory API can only be used by admins
A Service account is not an admin
If the service account shall act on behalf on the admin, you need to
enable G Suite Domain-wide Delegation (as you already did)
impersonate the service account as the admin by setting the user to be impersonated
In general, when you are using a service account you need to build the authentication flow, as explained in the documentation, that is you need to create JSON Web Token (JWT) specifying the user to impersonate.
A sample code snippet for Javascript:
const jwtClient = new google.auth.JWT(
privatekey.client_email,
null,
privatekey.private_key,
scopes,
user // User who will be impersonated (needs to be an admin)
);
await jwtClient.authorize();
return jwtClient;