Error while fetching Token with certificate & RSA Key in NodeJS - node.js

I am trying to fetch oauth token in NodeJS with key , certificate & client id.
Code for the same:
var form = {
client_id : CLIENT_ID,
grant_type: 'client_credentials',
}
var headers= {
'content-type': 'application/x-www-form-urlencoded',
}
var option = {
method: 'POST',
url: CERTIFICATE_URL + "/oauth/token",
headers,
form,
httpsAgent:new https.Agent({
cert: CLIENT_CERTIFICATE.replace(/\\n/g, '\n'),
key: CLIENT_CERTIFICATE_KEY.replace(/\\n/g, '\n')
})
};
request(option, function(error, response, body) {
var token = null;
console.log(error);
console.log(JSON.parse(body).access_token)
if(!error && response.statusCode == 200) {
token = JSON.parse(body).access_token;
} else {
console.log(error)
error = error | new Error(body);
}
cb(error, token);
});
But getting the following error :
Error: write EPROTO 140062523283264:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL alert number 40
2021-10-13T23:46:56.23+0530 [APP/PROC/WEB/0] OUT at WriteWrap.afterWrite [as oncomplete] (net.js:789:14) errno: 'EPROTO', code: 'EPROTO', syscall: 'write'
The certificate & key is generated & fetched from the cloud environment itself.
This is a x509 MTLS based authentication.

Was able to do it with axios library, request library seems to be deprecated.

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

Sign in with apple REST api keep getting [Request failed with status code 400] error

I am implementing apple sign in on my website
On my backend(Nodejs), I need to request an authentication token using https://appleid.apple.com/auth/token REST api.
I used Axios and coded as following
export const createSignWithAppleSecret = () => {
const token = jwt.sign({}, signWithApplePrivateKey, {
algorithm: 'ES256',
expiresIn: '1h',
audience: APPLE_DOMAIN,
issuer: APPLE_TEAM_ID,
subject: APPLE_SERVICE_ID,
keyid: APPLE_KEY_ID,
});
return token;
};
export const getAppleToken = async (code: string) =>
axios.post(
'https://appleid.apple.com/auth/token',
qs.stringify({
grant_type: 'authorization_code',
code,
client_secret: createSignWithAppleSecret(),
client_id: APPLE_SERVICE_ID,
redirect_uri: APPLE_REDIRECT_URI,
}),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
But I am getting Reqest failed with status code 400
Error: Request failed with status code 400\n at createError (/home/ubuntu/sooldamhwa/www/node_modules/axios/lib/core/createError.js:16:15)\n at settle (/home/ubuntu/sooldamhwa/www/node_modules/axios/lib/core/settle.js:17:12)\n at IncomingMessage.handleStreamEnd (/home/ubuntu/sooldamhwa/www/node_modules/axios/lib/adapters/http.js:260:11)\n at IncomingMessage.emit (events.js:327:22)\n at IncomingMessage.EventEmitter.emit (domain.js:485:12)\n at endReadableNT (_stream_readable.js:1201:12)\n at processTicksAndRejections (internal/process/task_queues.js:84:21)
The api endpoint is correct, and I have configured header as document instructed( https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens)
Could someone please let me know what I did wrong?

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

How to fix server connection using https client with basic auth and tls pfx certificate?

I am trying connect third part server with basic auth and pfx tls certificate using node express platform. I am not sure; Where do I need to set basic auth, cert file and header params?
For get operation call from remote server, I have tried to use, https client and tls tool.
Request requires ;
header = basic auth,schemaVersion, id, applicationName
In addition to sending the basic auth credentials, send the following in the HTTP Header: Content-Type: application/json
Accept: application/json
and also request require one additional parameter i.e. categories
onst https = require('https');
const options = {
hostname: 'https://yadda/cards/getAssets',
headers: {
Authorization: 'Basic ' + new Buffer(username + ':' + passw).toString('base64'),
schemaVersion: '2.0.0',
id: '0000000',
applicationName: 'yadda',
Accept: 'application/json',
'Content-Type': 'application/json',
},
pfx: fs.readFileSync('/somefile.cert.pfx'),
passphrase: 'passphrase',
categories: 'food',
};
https
.get(options, (response: any) => {
response.on('data', (d: any) => {
console.log(`BODY: `, d);
});
})
.on('error', (e: any) => {
console.error('Error: ', e);
});
// With Tls tool, I tried as;
var fs = require('fs');
var socket = tls.connect(options, () => {
console.log('client connected');
process.stdin.pipe(socket);
process.stdin.resume();
});
I would like to get connected with remote server and receive data in response; instead I am getting following error;
ERROR] Error: { Error: getaddrinfo ENOTFOUND https://yadd/cards/getAssets:443
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'https://yadda/cards/getAssets',
A hostname (like www.example.com) is expected here, not a URL. The string you gave will be used as hostname and a DNS lookup will fail:
ERROR] Error: { Error: getaddrinfo ENOTFOUND https://yadd/cards/getAssets:443

certificate issue in nodejs https request

I have the following error while making an https get request
{ Error: write EPROTO 101057795:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:openssl\ssl\s23_clnt.c:802:
at _errnoException (util.js:992:11)
at WriteWrap.afterWrite [as oncomplete] (net.js:864:14) code: 'EPROTO', errno: 'EPROTO', syscall: 'write' }
I am trying to make a request to corporate internal resource where proxy is not needed.
const request = require('request')
var token= myToken
request({
method: 'post',
url: 'https://myURL',
data: {
myData
},
headers: { 'Authorization': 'Bearer myToken' },
agentOptions: {
rejectUnauthorized: false,
},
}, function (error, response, body) {
if(error){
console.log('Error: ', error)
} else {
console.log(body)
}
})
I also have strict-ssl=false in my .npmrc.
What I have notices is that I can make the same call curl with no issues.
curl -k1 -XPOST -H "Authorization: Bearer %TOKEN%" "https://%URL% -d #data,json -H "content-type: application/json"
-k1 option in curl seems to fix the issue with the certificate.
What am I doing wrong in JavaScript?
It turned out to be a bug in node version 8. I finally found a solution here - https://github.com/nodejs/node/issues/16196
One needs to add the following into her code:
require("tls").DEFAULT_ECDH_CURVE = "auto"
request({
method: 'post',
url: 'https://myURL',
data: {
myData
},
headers: { 'Authorization': 'Bearer myToken' },
rejectUnauthorized: false,
}, function (error, response, body) {
if(error){
console.log('Error: ', error)
} else {
console.log(body)
}
});
If you don't want the TLS check all over the node project
set process.env.NODE_TLS_REJECT_UNAUTHORIZED=0;

Resources