89

I'm using Mikeal's request (https://github.com/mikeal/request) to make an https request to a server. However, I keep getting an authorization error of CERT_HAS_EXPIRED.

request({
        url: 'https://www.domain.com/api/endpoint',
        strictSSL: false
    }, function(error, response, body) {
        if(!error && response.statusCode == 200) {
            res.json(JSON.parse(body));
        } else {
           res.json(response.statusCode, {'error': 'error'})
        }
});

I've tried setting strictSSL to true and false, both output same error of CERT_HAS_EXPIRED. What is causing this issue and is there any way to fix it in nodejs?

wwwuser
  • 6,282
  • 8
  • 52
  • 64

7 Answers7

157

The best way to fix this:

Renew the certificate. This can be done for free using Greenlock which issues certificates via Let's Encrypt™ v2

A less insecure way to fix this:

'use strict';

var request = require('request');
var agentOptions;
var agent;

agentOptions = {
  host: 'www.example.com'
, port: '443'
, path: '/'
, rejectUnauthorized: false
};

agent = new https.Agent(agentOptions);

request({
  url: "https://www.example.com/api/endpoint"
, method: 'GET'
, agent: agent
}, function (err, resp, body) {
  // ...
});

By using an agent with rejectUnauthorized you at least limit the security vulnerability to the requests that deal with that one site instead of making your entire node process completely, utterly insecure.

Other Options

If you were using a self-signed cert you would add this option:

agentOptions.ca = [ selfSignedRootCaPemCrtBuffer ];

For trusted-peer connections you would also add these 2 options:

agentOptions.key = clientPemKeyBuffer;
agentOptions.cert = clientPemCrtSignedBySelfSignedRootCaBuffer;

Bad Idea

It's unfortunate that process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; is even documented. It should only be used for debugging and should never make it into in sort of code that runs in the wild. Almost every library that runs atop https has a way of passing agent options through. Those that don't should be fixed.

coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • 2
    What do you mean by [selfSignedRootCaPemCrtBuffer]? If I know where it is, how to supply the buffer? – Kim Honoridez Feb 17 '16 at 09:57
  • 2
    If you created a self-signed cert then you would use the pem version of that same self-issued root certificate as the buffer. – coolaj86 Feb 23 '16 at 22:39
  • 2
    Any ideas when the certificate is _not_ self signed nor expired, but node is complaining that it is expired? – El Yobo Jun 01 '20 at 00:10
89

Add this at the top of your file:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

DANGEROUS This disables HTTPS / SSL / TLS checking across your entire node.js environment. Please see the solution using an https agent below.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Dan Kohn
  • 33,811
  • 9
  • 84
  • 100
  • Thanks for the suggestion, but I already have this and it doesn't fix the issue. – wwwuser Dec 10 '13 at 16:19
  • 47
    Please unmark this as the solution. It is dangerous. – coolaj86 Nov 19 '15 at 06:45
  • 56
    Every time you use this dis-solution an NSA agent gets its wings. – coolaj86 Nov 19 '15 at 06:47
  • 17
    @CoolAJ86 There are valid situations to use this. Right now I'm waiting for an expired SSL certificate on a development API server to be updated. It is impeding my ability to do work, and this is a perfectly fine situation to just ignore the SSL issue in the interim. –  Jan 11 '17 at 14:42
  • @glenn-nelson No, that is not a valid situation. The correct solution would be one of http://stackoverflow.com/a/29397100/151312 – coolaj86 Jan 14 '17 at 20:58
  • 9
    @CoolAJ86 For my use-case, for which you lack all context, it is not applicable. Sorry, but your fundamentalism is not helping. –  Jan 16 '17 at 14:54
  • 1
    @glenn-nelson: There's some other way than "disable all https security throughout the entire application." For example, you could disable it in the `request` object that makes the calls with `.defaults()` or some other way. I'm not being a fundamentalist. I'm being a realist. Completely ignoring all certificate checking is not a good solution. There is some other solution which is better. But you said it's a dev env. I suppose the risk is relatively low... but I'd try to scope it somehow to the problematic cert or connections. – coolaj86 Jan 17 '17 at 17:00
  • 6
    @CoolAJ86 If I have a local application that only makes an HTTPS connection to a staging server in a local environment, there is absolutely no functional difference. Therefore this is an acceptable solution. –  Jan 18 '17 at 15:40
  • Or of course you can use it in CLI for your local dev server - `NODE_TLS_REJECT_UNAUTHORIZED=0 npm run dev` – gorodezkiy Nov 13 '21 at 00:57
70

If someone is having this issue today while using an old version of nodejs, this might be due to Lets's encrypt 30th sept. 2021 ROOT CA expiry already mentionned in this answer.

certificates are hardcoded in node source code and the new ISRG Root X1 certificate was only added in this commit.

One can either update their node version, use node --use-openssl-ca flag (assuming openssl certificates are up to date), use the http agent solution mentionned in other answers (I didn't test it), or set process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0 as a quick and dirty workaround.

Max
  • 979
  • 7
  • 9
  • 3
    An update of Node.js (in my case to the latest stable version v16.10.0) did the trick! I'm not sure, though, whether you picked the right commit, @max-akn, as my previous version was v8.17.0 and the commit you shared seems to be included from v8.0.0 onwards. – Rene Hamburger Oct 01 '21 at 12:28
  • Our production app is runnig on Heroku (Heroku-20 stack) and using Node 8.9.4. Also we use Angular 5.2.11 and Angular Universal for server-side rendering. Starting from October 1st 2021 our Angular Universal https requests suddenly stopped working and our pages were not rendering server-side.Simply by adding the "node --use-openssl-ca" flag in our package.json "start" script solved the problem: "start": "set NODE_ENV=production&& node --use-openssl-ca server.js" Thank you @Max Akn! – Felipe Micali Oct 14 '21 at 11:49
  • Thank you so much - this solved a problem I've been stuck on for a while. My code is initiated by a piece of legacy code which requires node v8. To solve this I installed node v14.18.2 using n, then set the system's node version back to v8 using n again. However once v14 was installed I could then call this directly with `$(n bin 14.18.2) index.js` – Tom Bailey Jan 29 '22 at 18:52
37

Here is a more concise way to achieve the "less insecure" method proposed by CoolAJ86

request({
  url: url,
  agentOptions: {
    rejectUnauthorized: false
  }
}, function (err, resp, body) {
  // ...
});
Robert Taylor
  • 2,860
  • 3
  • 21
  • 19
NTyler
  • 1,397
  • 1
  • 12
  • 20
  • 2
    If you import `request` from `https` then you don't even need `agentOptions`: `rejectUnauthorized` can be a property directly on the object passed to `request`. – derpedy-doo Apr 02 '20 at 05:15
15

I think the strictSSL: false should (should have worked, even in 2013) work. So in short are three possible ways:

  1. (obvious) Get your CA to renew the certificate, and put it on your server!
  2. Change the default settings of your request object:

    const myRequest = require('request').defaults({strictSSL: false})

    Many modules that use node-request internally also allow a request-object to be injected, so you can make them use your modified instance.
  3. (not recommended) Override all certificate checks for all HTTP(S) agent connections by setting the environment variable NODE_TLS_REJECT_UNAUTHORIZED=0 for the Node.js process.
conny
  • 9,973
  • 6
  • 38
  • 47
  • 1
    The 3. just saved me from monkey patching kibana 5 for plugin install through a MITM proxy with SSL interception. – Tensibai Mar 29 '17 at 08:40
1

Updating Nodejs will force request's cache to be flushed.

This worked for me when nothing else did.

factorypolaris
  • 2,757
  • 12
  • 15
  • This tipped me off to the solution for me. The certificate expired error started showing up after I installed NVM. Switching versions eliminated the error. – Bing Jan 10 '23 at 03:45
0

Try to temporarily modify request.js and harcode everywhere rejectUnauthorized = true, but it would be better to get the certificate extended as a long-term solution.

Angular University
  • 42,341
  • 15
  • 74
  • 81