I can run the users.list query and get the data response on the Api explorer for the Directory API (https://developers.google.com/workspace/explore?filter&discoveryUrl) and the Javascript query returns perfectly (but auth is done invisibly and probably using my superuser privileges, behind the scenes, so that does not really help me out).
I used the OAuth 2 Playground (https://developers.google.com/oauthplayground/) to create a bearer token for use with curl, and when I ran curl, it returned the data perfectly (but I don't want to use bearer tokens in production).
I took Google's sample code, and modified it to list users. When run, it looks like OAuth 2 is working. I get the 'Sign-in successful' log entry and I see a plausible 'auth' structure in the debugger.
When I step over the await service.users.list({ customer: 'my_customer' }), I catch a 400 'Execute error: GaxiosError: Invalid Input' error.
The list of scopes that I send to the google.auth.getClient in the code, is the same as on the Google Cloud Data Access page (https://console.cloud.google.com/auth/scopes), and also matches the domain-wide delegation that I gave to my 'service account' (https://admin.google.com/ac/owl/domainwidedelegation).
I saw a few old Stack Overflow notes about adding 'subject' line with my service account email address, but that made no difference and is probably an outdated clue.
Here is my code:
const { google } = require('googleapis'); // "googleapis": "^148.0.0",
const path = require('path');
let auth; // acquire a (OAuth 2) authentication client using a service account
await google.auth.getClient({
keyFile: path.join(__dirname, '../jwt.keys.json'),
scopes: [
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/admin.directory.group.member',
'https://www.googleapis.com/auth/admin.directory.user',
'https://www.googleapis.com/auth/admin.directory.user.readonly',
'https://www.googleapis.com/auth/cloud-platform',
],
// subject: '[email protected]',
}).then(
(authReturned) => {
auth = authReturned;
console.log('Sign-in successful');
},
(err) => { console.error('Error signing in', err); },
);
const service = google.admin({ version: 'directory_v1', auth });
let res =
await service.users.list({ customer: 'my_customer' }).then(
(response) => { console.log('Response: ', response); res = response; },
(err) => { console.error('Execute error: ', err); },
);
Here is the error:
Execute error: GaxiosError: Invalid Input
at Gaxios._request (/Users/stevepodell/WebstormProjects/weconnect-server/node_modules/gaxios/build/src/gaxios.js:142:23)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async JWT.requestAsync (/Users/stevepodell/WebstormProjects/weconnect-server/node_modules/google-auth-library/build/src/auth/oauth2client.js:429:18)
at async runSample (/Users/stevepodell/WebstormProjects/weconnect-server/controllers/groupEmailInsert.js:40:15) {
config: {
url: 'https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer',
method: 'GET',
apiVersion: '',
userAgentDirectives: [ [Object] ],
paramsSerializer: [Function (anonymous)],
headers: {
'x-goog-api-client': 'gdcl/7.0.0 gl-node/23.10.0',
'Accept-Encoding': 'gzip',
'User-Agent': 'google-api-nodejs-client/7.0.0 (gzip)',
Authorization: '<<REDACTED> - See `errorRedactor` option in `gaxios` for configuration>.'
},
params: { customer: 'my_customer' },
validateStatus: [Function (anonymous)],
retry: true,
responseType: 'unknown',
errorRedactor: [Function: defaultErrorRedactor],
retryConfig: {
currentRetryAttempt: 0,
retry: 3,
httpMethodsToRetry: [Array],
noResponseRetries: 2,
retryDelayMultiplier: 2,
timeOfFirstRequest: 1743618542024,
totalTimeout: 9007199254740991,
maxRetryDelay: 9007199254740991,
statusCodesToRetry: [Array]
}
},
response: {
config: {
url: 'https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer',
method: 'GET',
apiVersion: '',
userAgentDirectives: [Array],
paramsSerializer: [Function (anonymous)],
headers: [Object],
params: [Object],
validateStatus: [Function (anonymous)],
retry: true,
responseType: 'unknown',
errorRedactor: [Function: defaultErrorRedactor]
},
data: { error: [Object] },
headers: {
'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000',
'content-encoding': 'gzip',
'content-type': 'application/json; charset=UTF-8',
date: 'Wed, 02 Apr 2025 18:29:01 GMT',
server: 'ESF',
'transfer-encoding': 'chunked',
vary: 'Origin, X-Origin, Referer',
'x-content-type-options': 'nosniff',
'x-frame-options': 'SAMEORIGIN',
'x-xss-protection': '0'
},
status: 400,
statusText: 'Bad Request',
request: {
responseURL: 'https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer'
}
},
error: undefined,
status: 400,
code: 400,
errors: [ { message: 'Invalid Input', domain: 'global', reason: 'invalid' } ],
[Symbol(gaxios-gaxios-error)]: '6.7.1'
}
Debugging into Googles gaxios.io, I see the request going out:
{
"url": "https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer",
"method": "GET",
"apiVersion": "",
"userAgentDirectives": [
{
"product": "google-api-nodejs-client",
"version": "7.0.0",
"comment": "gzip"
}
],
"headers": {
"x-goog-api-client": "gdcl/7.0.0 gl-node/23.10.0",
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/7.0.0 (gzip)",
"Authorization": "Bearer ya29.c.c0ASRK0GaAq-1fZVK(...Redacted...)2P7QKmnk7VyorYYQ"
},
"params": {
"customer": "my_customer"
},
"retry": true,
"responseType": "unknown"
}
And the response
{
"config": {
"url": "https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer",
"method": "GET",
"apiVersion": "",
"userAgentDirectives": [
{
"product": "google-api-nodejs-client",
"version": "7.0.0",
"comment": "gzip"
}
],
"headers": {
"x-goog-api-client": "gdcl/7.0.0 gl-node/23.10.0",
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/7.0.0 (gzip)",
"Authorization": "Bearer ya29.c.c0ASRK0GY2-ws0m_X7ga(...Redacted...)cJkM0hmni3e"
},
"params": {
"customer": "my_customer"
},
"retry": true,
"responseType": "unknown"
},
"data": {
"error": {
"code": 400,
"message": "Invalid Input",
"errors": [
{
"message": "Invalid Input",
"domain": "global",
"reason": "invalid"
}
]
}
},
"headers": {
"alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000",
"content-encoding": "gzip",
"content-type": "application/json; charset=UTF-8",
"date": "Fri, 04 Apr 2025 16:39:39 GMT",
"server": "ESF",
"transfer-encoding": "chunked",
"vary": "Origin, X-Origin, Referer",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"x-xss-protection": "0"
},
"status": 400,
"statusText": "Bad Request",
"request": {
"responseURL": "https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer"
}
}
Any help, or even a link to an up-to-date documentation page, would be greatly appreciated.