93

I am looking for a way to add a custom CA to NPM so I can download from a location using said certificate (an internal git-server) without having to nuke all CA-checking with

npm config set strict-ssl false

Is there any way of achieving this or not? (if not: is there already a defect?)

FrankyBoy
  • 1,865
  • 2
  • 18
  • 32

2 Answers2

156

You can point npm to a cafile

npm config set cafile /path/to/cert.pem

You can also configure ca string(s) directly.

npm config set ca "cert string"

ca can be an array of cert strings too. In your .npmrc:

ca[]="cert 1 base64 string"
ca[]="cert 2 base64 string"

The npm config commands above will persist the relevant config items to your ~/.npmrc file:

cafile=/path/to/cert.pem

Note: these CA settings will override the default "real world" certificate authority lookups that npm uses. If you try and use any public npm registries via https that aren't signed by your CA certificate, you will get errors.

So, if you need to support both public https npm registries as well as your own, you could use curl's Mozilla based CA bundle and append your CA cert to the cacert.pem file:

curl -o ~/.npm.certs.pem https://curl.se/ca/cacert.pem
cat my-ca-cert.pem >> ~/.npm.certs.pem
npm config set cafile ~/.npm.certs.pem

Unfortunately npm's CA bundle is not editable as it's provided in the source code (thanks tomekwi) but nitzel has provided a generic Node.js method to append a certificate via the NODE_EXTRA_CA_CERTS environment variable.

RHEL Note: If you happen to be using a RHEL based distro and the RHEL packaged nodejs/npm you can use the standard update-ca-trust method as RedHat points their packages at the system CA's.

Matt
  • 68,711
  • 7
  • 155
  • 158
  • 3
    There is no bundle distributed with node – but there seems to be a list of them in the source: https://github.com/joyent/node/blob/master/src/node_root_certs.h – tomekwi Apr 08 '15 at 10:36
  • 4
    The github based url is deprecated. The new url is now: https://curl.haxx.se/ca/cacert.pem – JE42 Sep 29 '16 at 08:00
  • 7
    Try `NODE_DEBUG=tls,https,http npm -ddd command` check if your http connection has the CA setting and what the TLS handshake is doing – Matt Sep 03 '17 at 00:06
  • 1
    @Matt I am using `cacerts` from `%jdk%/%jre%/lib/security` of `Java`. It is showing proper path in `.npmrc`. Still error persist about `npm ERR! fatal: unable to access : SSL certificate problem: unable to get local issuer certificate`. Any idea about this how to solve it?? – Jimit Patel May 08 '18 at 10:11
  • 1
    @JimitPatel java has it's own keystore format for certs. The certs would need to be [exported with `keytool`](https://stackoverflow.com/q/652916/1318694) for use outside of java. – Matt Jun 03 '18 at 03:35
  • @Matt thanks for response. I found out the problem. I was using it in my Android Studio and by default it was using it's embedded Java rather than one which I kept in my environment. :) – Jimit Patel Jun 03 '18 at 06:09
  • As a sidenote, in case that `npm config set` does not work for you, try adding the `-g` (global) parameter and troubleshoot where do settings come from with `npm config get`. – Pavel Razgovorov Dec 29 '21 at 12:58
42

If Matts Answer isn't helping you, the following Windows PowerShell way worked for me and the similar approaches for CMD/Unix worked for other users:

Windows Powershell
$env:NODE_EXTRA_CA_CERTS=path\to\certificate.pem; npm install

DOS / Windows cmd

(pointed out by Marc in the comments)

set NODE_EXTRA_CA_CERTS=C:\\path\\to\\certificate.pem
npm install

Linux / Unix / Mac OS

(pointed out by Mike & mread1208 in the comments)

export NODE_EXTRA_CA_CERTS=/path/to/trusted/CA.pem
npm install
nitzel
  • 1,565
  • 14
  • 14
  • 1
    How did you specify a windows path with drive? `/path/to` would only work in Linux... – Marc Nov 25 '19 at 11:52
  • 2
    Gottit: `set NODE_EXTRA_CA_CERTS=C:\\bcp\\cafile.pem` (in DOS) – Marc Nov 25 '19 at 12:10
  • 2
    @Marc PowerShell accepts `/` and ``\`` (and uses `\`` instead of ``\`` to escape characters) *What a struggle to escape `\`` and ``\`` in markdown ._.* – nitzel Nov 25 '19 at 12:32
  • 7
    Am I missing something or isn't this answer much better than the accepted one? I don't want to "override" the default set, and it doesn't sound like the original question does either. I just want to add one cert to the truststore (my company's MITM cert). – DavidS May 24 '20 at 20:43
  • 4
    In Linux / Unix / OSX: `export NODE_EXTRA_CA_CERTS=/path/to/trusted/CA.pem` [credit](https://stackoverflow.com/a/47160447/667301) – Mike Pennington Aug 04 '20 at 16:53
  • How do we set the path in windows? .npmrc cafile=c:/folder1/folder2/folder3/caCert.pem or cafile=/folder3/caCert.pem npm config set cafile c:/folder1/folder2/folder3/caCert.pem or npm config set cafile c:/folder3/caCert.pem – user3380358 Sep 08 '20 at 04:40
  • @user3380358 Use the command lines in my answer. If you want to permanently set it, see the accepted answer from `Matt`. That occasionally didn't work for me, which is why I posted my alternative. – nitzel Sep 09 '20 at 11:05
  • 1
    @MikePennington's answer worked for me on Mac. I used FireFox to download the .pem file from the URL I was trying to reach. Then ran `export NODE_EXTRA_CA_CERTS=/path/to/downloaded/CA.pem`, and was able to get around the expired certificate issue! – mread1208 Mar 01 '22 at 14:45
  • One extra necessity in my case was to reboot the machine. Or some node.exe process probably, but on my machine not any node.exe process was running, so tried the reboot. (Windows, environment variable set as system variable via system properties, not via cli, but that shouldnt matter...) – Michael Mar 04 '22 at 21:10
  • @Michael That sounds odd to me. Maybe `npm` hung up before. Still odd.. however, I'm happy you managed to get it running :) Maybe your comment will help a dev in the future! – nitzel Mar 07 '22 at 13:55