Accept self-signed certificates for undici fetch

2.1k Views Asked by At

How do I do fetch('https://localhost:8888') for a locally running HTTP server with a self-signed cert (fetch coming from undici)?

4

There are 4 best solutions below

0
On

The trick is to use setGlobalDispatcher (getGlobalDispatcher can be used to grab the original one for later restoration).

import {
  fetch,
  setGlobalDispatcher,
  Agent,
} from 'undici'

setGlobalDispatcher(new Agent({
  connect: {
    rejectUnauthorized: false
  }
}))

fetch('https://localhost:8888').then(...)
0
On

You can also use the ProxyAgent class. The ProxyAgent class has an options.requestTls and options.proxyTls, which are not described in document. In order to use rejectUnauthorized : false options, just code like below:

import { ProxyAgent, request } from 'undici'

const proxyAgent = new ProxyAgent('my.proxy.server',{
    requestTls: {  // this is the key point
         rejectUnauthorized: false,
    }
})

const {  statusCode,  body } = await request('http://localhost:3000/foo', { dispatcher: proxyAgent })
for await (const data of body) {
  console.log('data', data.toString('utf8'))
}

Also check the test case Proxy via HTTP to HTTPS endpoint and the proxy-agent source code.This is the fixed pr

1
On

If you are using Node.js's built-in fetch, you can specify the dispatcher in the init options.

You still need to install undici (npm install undici) to be able to use a custom Agent.

import { Agent } from 'undici';

await fetch('https://localhost:8888', {
  dispatcher: new Agent({
    connect: {
      rejectUnauthorized: false,
    },
  }),
});
0
On

The issue with answers that suggest using rejectUnauthorized: false is that this makes the request unsecure.

I'd suggest you get the PEM base64'd certificate from the server/site you're trying to reach and include it through an agent when making your request:

const { Agent } = require('undici');

const PEM_CERTS = `{base64 certificate for https://localhost:8888}`;

/* 
    The certificate content should look like:
    -----BEGIN CERTIFICATE-----
    base64string
    -----END CERTIFICATE-----
*/

fetch('https://localhost:8888', {
    dispatcher: new Agent({
        connect: {
            ca: PEM_CERTS
        }
    })
}).then(response => {
    return response.text();
}).then(text => {
    console.log(text);
});

You can get the base64 certificate by accessing https://localhost:8888 through your browser, clicking on the "secure"/lock icon next to the URL and following your browser's steps to download the certificate as CRT or PEM. Open it as plain text to retrive the base64 content.

Or export it via command line, but you'll have to convert it from CER to base64 format yourself.

Alternatively, you can also install the certificate on your machine and you may not have to worry about this altogether.