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?
Note that I have also asked this question on StackOverflow (https://stackoverflow.com/questions/48766209/cant-use-proxy-to-do-jwt-authentication-with-googleapis).
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: StackOverflow
I've encounter this also,
setting HTTPS_PROXY isn't helping at all, as the docs says
Google _My Business_ customers, such as ours, that need to use Google APIs to make best use of this service should not be held hostage by a glaring external issue that was opened "May 30, 2017". And this external issue is begging to merge a proposed fix for the past 6+ months??
I just ran into this myself yesterday when promoting new code into our data center that fails simply because it's behind a corporate proxy. This is not a "feel good" story at all.
Update: https://github.com/axios/axios/pull/959 has been merged. I guess we are waiting for a new axios release?
A workaround I found is to clear the http_proxy env variables and instead run the node app in proxychains:
proxychains node app.js
with a proxychains.conf in the working directory such as:
strict_chain
tcp_read_time_out 15000
tcp_connect_time_out 8000
localnet 127.0.0.0/255.0.0.0
[ProxyList]
http {your proxy ip address} {your proxy port}
or change http to socks5 for socks proxy etc.
Most helpful comment
Google _My Business_ customers, such as ours, that need to use Google APIs to make best use of this service should not be held hostage by a glaring external issue that was opened "May 30, 2017". And this external issue is begging to merge a proposed fix for the past 6+ months??
I just ran into this myself yesterday when promoting new code into our data center that fails simply because it's behind a corporate proxy. This is not a "feel good" story at all.