Securing Cloud Functions using IAM + NodeJS application running on AppEngine - node.js

I need some help with example if possible of code changes to be done on my NodeJS server code running on AppEngine in order to allow it to securely access my cloud fucntions.
I created a cloud function and I have a public URL for it. I then went ahead and removed allUser access in the Permissions' tab of the function. Under Service account I have App Engine Default Service account` selected.
My server on AppEngine was calling the public URL of the CF and when `allUser' permission was there, everything was hunky dory. But when it was removed, I started getting 403 error.
I need help with code changes on NodeJS side to be able to invoke the cloud fucntion again please.
My CF and App engine are in the same project and in the same region.
My server code is as follows using an https library to make the post request.
const checkingData = JSON.stringify({
'check' : 123
})
const checkingOptions = {
hostname: MY_CLOUD_PUBLIC_URL,
port: 443,
timeout: 5000,
path: MY_CLOUD_URL_PATH,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
const checkRequest = https.request(checkingOptions, checkD => {
if (checkD.statusCode==200) { // OK?
checkD.on('data', d => {
// Do something useful with the data
})
})
checkRequest.write(checkingData);
checkRequest.end();
I have been trying to find an answer for this for days now and started having migranes because of this. Any help with example code would be much appreciated. Many thanks!
EDIT
I can see the token now! (Yayyy!)
I changed my checkingOptions to work with request-promise in the following way:
const checkingOptions = {
uri: 'https://'+process.env.CLOUD_URL+process.env.CHECK,
port: 443,
timeout: 5000,
body:checkingData,
json: true,
// path: process.env.CHECK,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
I am getting the following errors:
Unhandled rejection StatusCodeError: 401 - "\n<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\">\n<title>401 Unauthorized</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Unauthorized</h1>\n<h2>Your client does not have permission to the requested URL <code>/check</code>.</h2>\n<h2></h2>\n</body></html>\n"
2021-02-27 19:38:01 default[20210227t192944] at new StatusCodeError (/workspace/node_modules/request-promise-core/lib/errors.js:32:15)
2021-02-27 19:38:01 default[20210227t192944] at Request.plumbing.callback (/workspace/node_modules/request-promise-core/lib/plumbing.js:104:33)
2021-02-27 19:38:01 default[20210227t192944] at Request.RP$callback [as _callback] (/workspace/node_modules/request-promise-core/lib/plumbing.js:46:31)
2021-02-27 19:38:01 default[20210227t192944] at Request.self.callback (/workspace/node_modules/request/request.js:185:22)
2021-02-27 19:38:01 default[20210227t192944] at Request.emit (events.js:314:20)
2021-02-27 19:38:01 default[20210227t192944] at Request.<anonymous> (/workspace/node_modules/request/request.js:1154:10)
2021-02-27 19:38:01 default[20210227t192944] at Request.emit (events.js:314:20)
2021-02-27 19:38:01 default[20210227t192944] at IncomingMessage.<anonymous> (/workspace/node_modules/request/request.js:1076:12)
2021-02-27 19:38:01 default[20210227t192944] at IncomingMessage.emit (events.js:326:22)
2021-02-27 19:38:01 default[20210227t192944] at endReadableNT (_stream_readable.js:1241:12)
Do I need a middleware in my cloud function as well? My cloud function looks like the follow:
exports.check = functions.https.onRequest((req, res) => {
console.log('----CHECKING----');
res.status(200).send('Hello from checking');
})
IAM ROLES:
CLOUD FUNCTION > PERMISSIONS TAB

You have a great example in the documentation. If you want I adapt it to your code, it could look like to this
// Make sure to `npm install --save request-promise` or add the dependency to your package.json
const request = require('request-promise');
// Set up metadata server request
// See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenRequestOptions = {
uri: metadataServerTokenURL + MY_CLOUD_PUBLIC_URL,
headers: {
'Metadata-Flavor': 'Google'
}
};
const checkingData = JSON.stringify({
'check' : 123
})
const checkingOptions = {
uri: MY_CLOUD_PUBLIC_URL, //!!!changed here!!!
port: 443,
timeout: 5000,
path: MY_CLOUD_URL_PATH,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': checkingData.length,
}
}
request(tokenRequestOptions).then((token) => {
request(checkingOptions).auth(null, null, true, token).then((response) => { //!!!changed here!!!
checkD.on('data', d => {
// Do something useful with the data
})
})
.catch((error) => {
res.status(400).send(error);
}); => {
})
checkRequest.write(checkingData);
checkRequest.end();
Don't forget to add the role role/cloudfunctions.invoker to the App Engine default service account, either at the project level or at the Cloud Functions level.
EDIT 1
Correct. request-promise has been deprecated for year. What alternative? I absolutely don't know because NodeJS hurts me (as I said in the comment).
As a lazy man, I found an alternative. I found the request-promise in the Cloud Run documentation. But you have to know that Cloud Run and Cloud Functions are very closed (they share the same underlying platform). I take my chance with Cloud Functions authentication documentation and bingo! There is an example with node-fetch
const fetch = require('node-fetch');
const MY_CLOUD_PUBLIC_URL = '....'
const metadataServerTokenURL = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
// Fetch the token
const tokenResponse = await fetch(metadataServerTokenURL + MY_CLOUD_PUBLIC_URL, {
headers: {
'Metadata-Flavor': 'Google',
},
});
const token = await tokenResponse.text();
console.log(token)
const checkingData = JSON.stringify({
'check' : 123
})
// Provide the token in the request to the receiving function
try {
const functionResponse = await fetch(MY_CLOUD_PUBLIC_URL, {
method: 'post',
body: checkingData,
headers: {
'Content-Type': 'application/json',
Authorization: `bearer ${token}`},
});
console.log(await functionResponse.text());
} catch (err) {
console.error(err);
}
Add your check functions and it should work now!

Related

Problems with getting Apple Pay payment session

A year ago we implemented ApplePay on the web in our project and everything worked just fine. But now it's unstable and payment can be successful on the third try sometimes. We are facing an ECONNRESET error while requesting POST https://apple-pay-gateway.apple.com/paymentservices/startSession and an error message “Payment not completed” on the client side
Error: read ECONNRESET at TLSWrap.onStreamRead (internal/stream_base_commons.js:209:20) {
errno: -104,
code: 'ECONNRESET',
config: {
url: 'https://apple-pay-gateway.apple.com/paymentservices/startSession',
method: 'post',
data: '{"merchantIdentifier":"merchant.com.xxxxxxxx","displayName":"xxxxxxxxxx","initiative":"web","initiativeContext":"xxxxxxxx.xxx","domainName":"xxxxxxxx.xxx"}',
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'User-Agent': 'axios/0.19.2',
'Content-Length': 191
}
},
...
response: undefined,
isAxiosError: true,
Client side code:
applePaySession.onvalidatemerchant = async (event) => {
try {
const data = {
url: event.validationURL,
method: 'post',
body: {
merchantIdentifier,
displayName,
initiative: "web",
initiativeContext: window.location.hostname
},
json: true,
}
const merchantSession = await this.$axios.$post('/apple_pay_session', data);
if (merchantSession && merchantSession.merchantSessionIdentifier) {
applePaySession.completeMerchantValidation(merchantSession)
} else {
applePaySession.abort();
}
} catch (error) {
logReqError(error)
applePaySession.abort();
}
};
Server side:
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
keepAlive: true,
cert: fs.readFileSync(`uploads/apple_pay/${id}/certificate.pem`),
key: fs.readFileSync(`uploads/apple_pay/${id}/private.key`)
});
const sessionRes = await axios({
url: request.body.url,
method: request.body.method.toLowerCase(),
data: request.body.body,
headers: {'Content-Type': 'application/json'}, httpsAgent
})
We checked the status of Merchant Domain - it's verified, Apple Pay Payment Processing Certificate and Apple Pay Merchant Identity Certificate are valid. I also checked project code with the official documentation, as well as with other sources.
I hope anyone has had a similar problem. Any code samples or guesses will be helpful anyway

Use google calendar API and Getting 401 error message with Axios get

When developing the Alexa skill. I'm trying to use Axios get to get the whole day's events information from google calendar api. When I redo the account linking, it works well. I thought the asscessToken could only last for 2 hours, and I get the 401 error message because the token is expired.
Here is my Axios code
const getEvents = async (url, accessToken) => {
try {
const config = {
headers: {'Authorization': 'Bearer ' + accessToken}
};
return await Axios.get(url, config);
} catch (error) {
console.log('Error getting events');
console.error(error);
}
}
Code for my url and the asscesstoken
const url = EVENTS_URL + "?orderBy=updated&timeMin=" + timeMin + "&timeMax="
+ timeMax;
const accessToken =
handlerInput.requestEnvelope.context.System.user.accessToken;
Error Message:
ERROR { Error: Request failed with status code 401
at createError (/var/task/node_modules/axios/lib/core/createError.js:16:15)
at settle (/var/task/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/var/task/node_modules/axios/lib/adapters/http.js:260:11)
at IncomingMessage.emit (events.js:203:15)
at IncomingMessage.EventEmitter.emit (domain.js:448:20)
at endReadableNT (_stream_readable.js:1145:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
method: 'get',
headers:
{ Accept: 'application/json, text/plain, */*',
Authorization: 'Bearer undefined',
'User-Agent': 'axios/0.21.1' },

Making POST call outside of the GCP environment to create workload identity

I need to access GCP resources outside of the GCP environment from AWS using a AWS lambda. So, I found this document [accessing GCP resources from AWS][1] which provides a way to access the GCP resources and asks to create a workload identity pool.
I need to create a Workload identity pool in GCP using a REST API call. The REST API call has to run outside of the GCP environment, that is, in this case from the AWS environment. My GCP's IAM user doesn't have privileges to create a workload identity pool (due to org policy reasons). But, I've a service account which has admin privileges to create a workload identity pool and all the required permissions to access the required resources once the pool is created.
I'm a newbie to GCP and figuring out ways of calling a POST REST API call using my service account credentials. Any help is much appreciated.
Edited
Pasting the sample code I've been trying to make the REST call.
const {google} = require('googleapis');
const util = require('util');
const https = require('https');
const aws4 = require('aws4');
const auth = new google.auth.GoogleAuth({
keyFile: 'serviceAccountCreds.json',
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
});
async function createSignedRequestParams(jsonBodyParams) {
const getAccessToken = await auth.getAccessToken();
console.log(`createSignedRequestParams() - this.credentials:${getAccessToken !== null}`);
// Set up the request params object that we'll sign
const requestParams = {
path: '/v1beta/projects/serviceAccountdev/locations/global/workloadIdentityPools?workloadIdentityPoolId=12345',
method: 'POST',
host: 'iam.googleapis.com',
headers: { 'Content-Type': 'application/json' },
body: jsonBodyParams
};
console.log(`createSignedRequestParams() - (signed) requestParams:${util.inspect(requestParams)}`);
return requestParams;
}
const jsonBodyParams = {
"description": "createWorkloadIdentityPool",
"display-name": "devAccount"
};
async function request(requestParams, jsonBodyParams) {
console.log(`request() requestParams:${util.inspect(requestParams)} jsonBodyParams:${jsonBodyParams}`);
// return new pending promise
return new Promise((resolve, reject) => {
const req = https.request(requestParams);
if (['POST', 'PATCH', 'PUT'].includes(requestParams.method)) {
req.write(jsonBodyParams);
}
req.end();
// Stream handlers for the request
req.on('error', (err) => {
console.log(`request() req.on('error') err:${util.inspect(err)}`);
return reject(err);
});
req.on('response', (res) => {
let dataJson = '';
res.on('data', chunk => {
dataJson += chunk;
});
res.on('end', () => {
const statusCode = res.statusCode;
const statusMessage = res.statusMessage;
const data = JSON.parse(dataJson);
console.log(`request() res.on('end')`, { statusCode, statusMessage, data });
resolve({ statusMessage, statusCode, data });
});
});
});
}
async function postTheRequest(reqParams, jsonBodyParams) {
try {
const response = await request(reqParams, jsonBodyParams);
return response;
} catch (error) {
console.log(error);
}
}
reqParams = createSignedRequestParams(jsonBodyParams);
postTheRequest(reqParams, jsonBodyParams);
output of the above code
[Running] node "c:\Users\av250044\.aws\GCP_Code_examples\registerTheWorkloadIdentifier.js"
request() requestParams:Promise { <pending> } jsonBodyParams:[object Object]
request() req.on('error') err:{ Error: connect ECONNREFUSED 127.0.0.1:443
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1106:14)
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 443 }
{ Error: connect ECONNREFUSED 127.0.0.1:443
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1106:14)
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 443 }
Wondering if I'm passing the PATH and host are correct. Please let me know your thoughts on my code sample.
[1]: https://cloud.google.com/iam/docs/access-resources-aws#iam-workload-pools-add-aws-rest

'request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate. NodeJS

Node Version - v12.16.1
NPM Version- 6.13.4
I am using below code in Nodejs to get VM's list from google cloud using google cloud compute library. Following this link - https://github.com/googleapis/nodejs-compute#before-you-begin
// By default, the client will authenticate using the service account file
// specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable and use
// the project specified by the GCLOUD_PROJECT environment variable. See
// https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
const Compute = require('#google-cloud/compute');
rejectUnauthorized: false;//add when working with https sites
requestCert: false;//add when working with https sites
agent: false;//add when working with https sites
// Creates a client
const compute = new Compute();
async function getVmsExample() {
// In this example we only want one VM per page
const options = {
maxResults: 1,
};
const vms = await compute.getVMs(options);
return vms;
}
// Run the examples
exports.main = async () => {
const vms = await getVmsExample().catch(console.error);
if (vms) console.log('VMs:', vms);
return vms;
};
if (module === require.main) {
exports.main(console.log);
}
I have already fulfilled all the prerequisites but whwnever I run the code I get the below error-
FetchError: request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate
at ClientRequest.<anonymous> (C:\Users\username\Desktop\Full-Stack\NodeJS\node-examples\node_modules\node-fetch\lib\index.js:1455:11)
at ClientRequest.emit (events.js:311:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:311:20)
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
message: 'request to https://www.googleapis.com/oauth2/v4/token failed, reason: unable to get local issuer certificate',
type: 'system',
errno: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
code: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY',
config: {
method: 'POST',
url: 'https://www.googleapis.com/oauth2/v4/token',
data: {
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJub2RlanNhY2NvdW50QGNvZ2VudC1jYXNlLTI0MjAxNC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jb21wdXRlIiwiYXVkIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3Y0L3Rva2VuIiwiZXhwIjoxNTg3OTU4NDcwLCJpYXQiOjE1ODc5NTQ4NzB9.QSn0bSjHtph4aHGZcXIkWhbbUxampHSOE1BsDkI8dZOah12ICHFOZV0zwrngCPbTMr4MIfTAE7s8fLESjCUEq7lPSvB0uTqU5Lr3fI4FUUEqOGp56821Lh68Z8stWmKb-9HV85h7Ub0aSkJdnezYMcK_-FPu__a3ZLeP3lEnjJu9292DtctGT73XvHaeDTMFiHSI10BlJ2LIPds5lC6XM5I4f6W-4UH0VhUgLo1uCGxJJj0jnkQZbjp11l8KSwsMuIMFvug8G6Y5OKP1E4Ef1EKoEBFGC-vjIjaCPiqkFv4U1yh8xc7ShXh2MBQ8eyUZY1OvDNO4IXexQ-RoWBt0pQ'
},
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
responseType: 'json',
params: [Object: null prototype] {},
paramsSerializer: [Function: paramsSerializer],
body: '{"grant_type":"urn:ietf:params:oauth:grant-type:jwt-bearer","assertion":"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJub2RlanNhY2NvdW50QGNvZ2VudC1jYXNlLTI0MjAxNC5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInNjb3BlIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vYXV0aC9jb21wdXRlIiwiYXVkIjoiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3Y0L3Rva2VuIiwiZXhwIjoxNTg3OTU4NDcwLCJpYXQiOjE1ODc5NTQ4NzB9.QSn0bSjHtph4aHGZcXIkWhbbUxampHSOE1BsDkI8dZOah12ICHFOZV0zwrngCPbTMr4MIfTAE7s8fLESjCUEq7lPSvB0uTqU5Lr3fI4FUUEqOGp56821Lh68Z8stWmKb-9HV85h7Ub0aSkJdnezYMcK_-FPu__a3ZLeP3lEnjJu9292DtctGT73XvHaeDTMFiHSI10BlJ2LIPds5lC6XM5I4f6W-4UH0VhUgLo1uCGxJJj0jnkQZbjp11l8KSwsMuIMFvug8G6Y5OKP1E4Ef1EKoEBFGC-vjIjaCPiqkFv4U1yh8xc7ShXh2MBQ8eyUZY1OvDNO4IXexQ-RoWBt0pQ"}', validateStatus: [Function: validateStatus]
}
}
I tried npm config set strict-ssl false also.
Have anyone any idea what is wrong?
Thanks for help!
When you initiate the client you can either set strictSSL to false ( you did ) or pass in the new valid certificates.
Set strictSSL to false ( which you already did ) and then update cert files (you should be able to export them here - https://baltimore-cybertrust-root.chain-demos.digicert.com/)
This link http://registry.npmjs.org/npm could be block by IT admin in your organization. ( Please Verify )
In addition,You can refer to this stack overflow case as reference for the fix with secure manner and some various alternatives which might assist you for getting direction for the solution.

NodeJS axios request self signed works in browser but not in jest supertest case

I am building a NodeJS app that makes calls to an external API. The external API uses a self-signed certificate. I tried setting the environment variable process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'. This works to ignore the certificate verification when using the app normally. However, a request to the same endpoint does NOT work when calling the NodeJS route with the Jest Supertest agent.
There is a certificate verification error when running the Jest Supertest case. Is there a way to accept self-signed certificates when sending requests using the Supertest agent?
npm test
Error: Error: SSL Error: DEPTH_ZERO_SELF_SIGNED_CERT
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestResponse (/home/node/app/node_modules/request/request.js:948:10)
at ClientRequest.emit (events.js:311:20)
at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:603:27)
at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)
at TLSSocket.socketOnData (_http_client.js:476:22) undefined
NodeJS internal route
Works when accessing route via the browser, but not when running Jest Supertest. The internal route is /internal and that works, but when that code subsequently sends a request to the external API that has a self-signed certificate, the self-signed certificate causes a 500 error message.
router.get('/internal', (req, res, next) => {
// Set request values that are specific to this route
const requestOptionsData = { method: `GET`, endpoint: `/external` };
try {
httpCtrl.makeRequest(requestOptionsData).then(result => {
if (result.error) {
return res.status(result.status).json(result.error.message || result.error);
}
return res.status(result.status).json(result);
}).catch((error) => {
console.error(error);
return res.status(500).send(error);
});
} catch (e) {
console.error(e);
return res.status(500).send(e);
}
});
NodeJS controller
A wrapper function to make axios requests to external API
httpCtrl.makeRequest = async (requestOptionsData) => {
let result = {};
// Set request options
const requestOptions = httpCtrl.setApiRequestOptions(requestOptionsData);
let response;
try {
response = await axios(requestOptions);
} catch(e) {
result.error = e.toJSON() || e;
console.error(result.error);
result.status = 500;
return result;
}
result.status = response && response.status || 500;
result.data = response && response.data || {};
return result;
}
JEST Supertest
Test that causes certificate error
const app = require('../app.js');
const supertest = require('supertest');
describe('API routes', () => {
it('GET internal NodeJS route', async done => {
agent
.get('/internal')
.set('Accept', 'application/json')
.send()
.expect(200)
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).toBe(200);
return done();
});
});
});
UPDATE:
I tried removing NODE_TLS_REJECT_UNAUTHORIZED and setting rejectUnauthorized to false in the axios agent config but still having the same problem. The connection works when using the app via the browser but does work with supertest.
const agent = new https.Agent({
rejectUnauthorized: false
});
const options = {
url: url,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${requestOptionsData.jwt}`,
'Host': process.env.ADMIN_API_BASE_URL
},
method: requestOptionsData.method || `GET`,
httpsAgent: agent
}
Here is the error with this agent configuration:
Error: Error: self signed certificate
at Object.dispatchError (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:54:19)
at EventEmitter.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:675:20)
at EventEmitter.emit (events.js:323:22)
at Request.<anonymous> (/home/node/app/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:384:47)
at Request.emit (events.js:311:20)
at Request.onRequestError (/home/node/app/node_modules/request/request.js:877:8)
at ClientRequest.emit (events.js:311:20)
at TLSSocket.socketErrorListener (_http_client.js:426:9)
at TLSSocket.emit (events.js:311:20)
at emitErrorNT (internal/streams/destroy.js:92:8) undefined
console.error controllers/http.ctrl.js:50
I was able to solve this with the solution in this github issue.
I solved it by adding testEnvironment: 'node', to jest.config.js file.
https://github.com/axios/axios/issues/1180

Resources