How to configure axios to use SSL certificate?

170,598

Solution 1

Old question but chiming in for those who land here. No expert. Please consult with your local security gurus and what not.

Axios is an http(s) client and http clients usually participate in TLS anonymously. In other words, the server accepts their connection without identifying who is trying to connect. This is different then say, Mutual TLS where both the server and client verify each other before completing the handshake.

The internet is a scary place and we want to protect our clients from connecting to spoofed public endpoints. We do this by ensuring our clients identify the server before sending any private data.

// DO NOT DO THIS IF SHARING PRIVATE DATA WITH SERVICE
const httpsAgent = new https.Agent({ rejectUnauthorized: false });

This is often posted (and more egregiously upvoted) as the answer on StackOverflow regarding https client connection failures in any language. And what's worse is that it usually works, unblocks the dev and they move on their merry way. However, while they certainly get in the door, whose door is it? Since they opted out of verifying the server's identity, their poor client has no way of knowing if the connection they just made to the company's intranet has bad actors listening on the line.

If the service has a public SSL cert, the https.Agent usually does not need to be configured further because your operating system provides a common set of publicly trusted CA certs. This is usually the same set of CA certs your browser is configured to use and is why a default axios client can hit https://google.com with little fuss.

If the service has a private SSL cert (self signed for testing purposes or one signed by your company's private CA to protect their internal secrets), the https agent must be configured to trust the private CA used to sign the server cert:

const httpsAgent = new https.Agent({ ca: MY_CA_BUNDLE });

where MY_CA_BUNDLE is an array of CA certs with both the server cert for the endpoint you want to hit and that cert's complete cert chain in .pem format. You must include all certs in the chain up to the trust root.


Where are these options documented?

HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module.

Therefore options passed to the https.Agent are a merge of the options passed to tls.connect() and tls.createSecureContext().

Solution 2

Create a custom agent with SSL certificate:

const httpsAgent = new https.Agent({
  rejectUnauthorized: false, // (NOTE: this will disable client verification)
  cert: fs.readFileSync("./usercert.pem"),
  key: fs.readFileSync("./key.pem"),
  passphrase: "YYY"
})

axios.get(url, { httpsAgent })

// or

const instance = axios.create({ httpsAgent })

From https://github.com/axios/axios/issues/284

Solution 3

These configuration worked for me (In a Mutual Authentication scenario).

const httpsAgent = new https.Agent({
  ca: fs.readFileSync("./resource/bundle.crt"),        
  cert: fs.readFileSync("./resrouce/thirdparty.crt"),
  key: fs.readFileSync("./resource/key.pem"), 
})

Note: bundle.crt was prepared from provided certificates (root,intermediate,end entry certificate). Unfortunately no clear documentation found in this regards.

Solution 4

For me, when my application is running in development mode, I have disabled rejectUnauthorized directly in axios.defaults.options. This works very well. be careful and use this only in developer mode.

import https from 'https'
import axios from 'axios'
import config from '~/config'

/**
 * Axios default settings
 */
axios.defaults.baseURL = config.apiURL

/**
 * Disable only in development mode
 */
if (process.env.NODE_ENV === 'development') {
  const httpsAgent = new https.Agent({
    rejectUnauthorized: false,
  })
  axios.defaults.httpsAgent = httpsAgent
  // eslint-disable-next-line no-console
  console.log(process.env.NODE_ENV, `RejectUnauthorized is disabled.`)
}

Solution 5

This what worked for me , using axios with nodejs + express

exports.test_ssl = async (req,res) => { 
   
let cert_file = fs.readFileSync("./ssl/my_self_signed_certificate.crt")
let ca_file = fs.readFileSync("./ssl/my_self_signed_certificate_ca.crt")
const agent = new https.Agent({
    requestCert: true,
    rejectUnauthorized: true,
    cert: cert_file,
    ca: ca_file
});
const options = {
    url: `https://51.195.45.154/test`,  // <---this is  a fake ip do not bother
    method: "POST",
    httpsAgent : agent,
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/txt;charset=UTF-8'
    },
    data: {}
};


console.log(cert_file.toString())

axios(options)
.then(response => {
    payload = response.data ;
    return res.status(200).send({"status":1});
}).catch(err => {
    console.log(err);
    return false
});

}
Share:
170,598
Jemi Salo
Author by

Jemi Salo

I am a Software Developer at Smartly.io Solutions Oy. I am a web developer with a breadth of knowledge in full stack development and a depth of knowledge in React development. During my career I've maintained multiple projects as a full stack developer. Over more than two years of experience I've developed a special affinity for React application development.

Updated on July 05, 2022

Comments

  • Jemi Salo
    Jemi Salo almost 2 years

    I'm trying to make a request with axios to an api endpoint and I'm getting the following error: Error: unable to verify the first certificate

    It seems the https module, which axios uses, is unable to verify the SSL certificate used on the server.

    When visiting the server with my browser, the certificate is valid and I can see/download it. I can also make requests to the api on my browser through https.

    I can work around it by turning off verification. This code works.

    const result = await axios.post(
        `https://${url}/login`,
        body,
        {
          httpsAgent: new https.Agent({
            rejectUnauthorized: false
          })
        }
      )
    

    Problem is, this doesn't verify the SSL certificate and therefore opens up security holes.

    How can I configure axios to trust the certificate and correctly verify it?

  • srquinn
    srquinn over 5 years
    rejectUnauthorized: false disables client verification which is one of the OPs primary concerns.
  • Jemi Salo
    Jemi Salo over 5 years
    This finally worked for me after I downloaded the cert and its chain. I had previously failed, because I only downloaded the certificate for the service I wanted to use. For anyone struggling like I was: make sure you download the whole chain as .pem.
  • Suge
    Suge almost 5 years
    @JemiSalo How to get whole chain of my self signed certificate? I solve id by doing like that: const httpsAgent = new https.Agent({ ca: fs.readFileSync(certPath) });
  • pomeh
    pomeh over 4 years
    down voted as it's not wat the OP ask for. This answer, while still correct (except about rejectUnauthorized), is about client certificate, where OP want to verify server certificate
  • rawplutonium
    rawplutonium almost 4 years
    to create a bundle just copy the contents of the certificates provided in reverse order into a text file. in unix the command would be in your case : cat thirdparty.crt other.crt > bundle.crt where the name of the bundle doesn't really matter.
  • jambox
    jambox over 3 years
    Also I think the key parameter is a bit strange, what is that key of?
  • srquinn
    srquinn over 3 years
    Should be noted that this is safe if your server is colocated on localhost, but not safe when calling a public endpoint over the interwebs.
  • user1974458
    user1974458 over 3 years
    Where on Earth is this documented? I can't find any reference to a "ca" option in the docs for https.Agent.
  • srquinn
    srquinn about 3 years
    @user1974458 Its super confusing, updated the answer with doc links for options
  • Magnus
    Magnus about 3 years
    I'm really confused here. Why is my browser able to trust a private CA, but axios running from a node script on the same machine is not?!
  • srquinn
    srquinn about 3 years
    @Magnus Both have to be configured to trust the private CA. You don't provide enough information about your environment to understand why your browser trusts the CA and your nodejs client does not. Post in another question and happy to help
  • Magnus
    Magnus about 3 years
    @srquinn Thanks for the offer -- here is the full question: stackoverflow.com/questions/67488917/…
  • onoya
    onoya almost 3 years
    Thank you. This worked for me but had to change axios.defaults.options to axios.defaults.httpsAgent
  • Henrique Van Klaveren
    Henrique Van Klaveren over 2 years
    Thanks i have fixed. <o/
  • radiorz
    radiorz over 2 years
    pleace tell me what is the other.crt? @rawplutonium
  • Shafqat Bari
    Shafqat Bari over 2 years
    from where we can import https ?? in react native
  • Shafqat Bari
    Shafqat Bari over 2 years
    from where you have done import of https? in React Native
  • Shafqat Bari
    Shafqat Bari over 2 years
    from where you have done import of https? in React Native
  • Shafqat Bari
    Shafqat Bari over 2 years
    from where you have done import of https? in React Native
  • EdwinN1337
    EdwinN1337 over 2 years
    its a nodejs core module, won't work in react-native
  • Henrique Van Klaveren
    Henrique Van Klaveren over 2 years
    @ShafqatBari the https module is native from nodejs.
  • srquinn
    srquinn over 2 years
    This answer has rejectUnauthorized: false which turns off the identity check of the server and exposes your client to Man In the Middle attacks. See accepted answer, you should not be doing this in production workloads.
  • Nassim
    Nassim over 2 years
    @srquinn thanks fixed