I have a NodeJS API working behind a corporate proxy and I have been trying to do authentication with Google with their NodeJS client:
const google = require('googleapis');
function getServiceAccountInfo() {
return {
type: 'service_account',
project_id: 'XXXXX',
private_key_id: 'XXXXXX',
private_key: 'XXXX',
client_email: 'XXXX',
client_id: 'XXXX',
auth_uri: 'XXXX',
token_uri: 'XXXX',
auth_provider_x509_cert_url: 'XXXX',
client_x509_cert_url: 'XXXXX'
};
}
const SCOPES = 'https://www.googleapis.com/auth/firebase.messaging';
let proxy2 = {
host: 'proxy.hkcsl.net',
port: 8080
};
const proxy3 = {
proxy: 'http://172.25.2.6:8080'
}
const proxy4 = {
proxy: {
host: '172.25.2.6',
port: 8080,
auth: {
username: '',
password: '',
},
}
}
process.env.HTTPS_PROXY = 'https://172.25.2.6:8080';
process.env.https_proxy = 'https://172.25.2.6:8080';
process.env.HTTP_PROXY = 'http://172.25.2.6:8080';
process.env.http_proxy = 'http://172.25.2.6:8080';
google.options({
proxy: proxy4.proxy
});
const key = getServiceAccountInfo();
const jwtClient = new google.auth.JWT(
key.client_email,
undefined, // null,
key.private_key,
SCOPES,
undefined, // null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
console.error(err);
return;
}
console.log(tokens.access_token);
});
However, no matter how I configure the proxy option, I still either get a timeout error or something like
ERROR Error: write EPROTO 101057795:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:openssl\ssl\s23_clnt.c:827:
Some people managed to fix it by changing the port to 443 but it doesn't apply to my case since that port is not available to me inside the server. And I've already referenced on the discussions and solutions proposed here:
StackOverflow: node-request - Getting error “SSL23_GET_SERVER_HELLO:unknown protocol”
googleapis: There is no facility for passing a proxy to the oauth2client
Axios: Request to HTTPS with HTTP proxy fails
Using jwtClient.authenticate() behind a proxy results in ETIMEDOUT error
It also seems like Vue is also encountering a similar problem yesterday, they changed from using axios to using request instead. Is there a similar workaround for googleapis too?
After referencing on the workaround regarding the proxy issues with axios, which google-api-nodejs-client
(i.e. googleapis
) is using, and crawling through the source code of google-auth-library-nodejs
(jwtclient.ts) and node-gtoken
(index.ts), I wrote the following method to request token from Google manually as a temporary workaround:
const axios = require('axios-https-proxy-fix');
const querystring = require('querystring');
const jws = require('jws');
const GOOGLE_TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
const GOOGLE_REVOKE_TOKEN_URL =
'https://accounts.google.com/o/oauth2/revoke?token=';
const SCOPES = 'https://www.googleapis.com/auth/firebase.messaging';
const PROXY = {
host: '172.25.2.6',
port: 8080,
auth: {
username: '',
password: '',
}
};
function getServiceAccountInfo() {
return {
type: 'service_account',
project_id: 'XXXX',
private_key_id: 'XXXX',
private_key: 'XXXX',
client_email: 'XXXX',
client_id: 'XXXX',
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://accounts.google.com/o/oauth2/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url: 'XXXX'
};
}
function requestToken(client_email, private_key) {
const iat = Math.floor(new Date().getTime() / 1000);
const additionalClaims = {};
const payload = Object.assign(
{
iss: client_email,
scope: SCOPES,
aud: GOOGLE_TOKEN_URL,
exp: iat + 3600,
iat,
sub: undefined
},
additionalClaims);
const signedJWT =
jws.sign({header: {alg: 'RS256'}, payload, secret: private_key});
return axios({
method: 'post',
url: GOOGLE_TOKEN_URL,
data: querystring.stringify({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: signedJWT
}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
proxy: PROXY
})
.then(r => {
const body = r.data;
console.log(body);
return body.access_token;
})
.catch(e => {
const body = (e.response && e.response.data) ? e.response.data : {};
let err = e;
if (body.error) {
const desc =
body.error_description ? `: ${body.error_description}` : '';
err = new Error(`${body.error}${desc}`);
}
throw err;
});
}
const key = getServiceAccountInfo();
requestToken(key.client_email, key.private_key);
Reference: GitHub
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With