How to fix “Refused to connect to xxx because it violates the following Content Security Policy directive” on Heroku

I’ve deployed a MERN stack app to Heroku: Mongo DB, Express.js, React.js, Node.js.

The app uses Google Fonts and Stripe Checkout.

I’ve built the React app via Create React App.

My last deploy went wonkers. The app didn’t load any JavaScript because of Content-Security-Policy failures.

In this post I’ll show you how to fix those errors and how to successfully re-deploy your MERN app to Heroku.

What is Content-Security-Policy?

Content-Security-Policy is the name of a HTTP response header that modern browsers use to enhance the security of the document (or web page). The Content-Security-Policy header allows you to restrict how resources such as JavaScript, CSS, or pretty much anything that the browser loads. 1

How to Fix React/Create React App

In production, React will embed the React app as an inline script into index.html.

This leads to the following error:

“Refused to execute inline script because it violates the following Content Security Policy directive: “script-src ‘self’”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-5='), or a nonce (‘nonce-…') is required to enable inline execution.”

To fix that, you can disable inline-scripts.
Add an environment variable to your React app. The easiest way is to create a new file called .env and add INLINE_RUNTIME_CHUNK=false to the file.

For deployment to Heroku you’ll need to add the variable to your Heroku configuration, see Configuration and Config Vars.

Example using the Heroku CLI:

heroku config:set INLINE_RUNTIME_CHUNK=false

How to Fix CSP

You’ll need helmet for your Express.js/Node.js server:

const express = require('express')
const helmet = require('helmet')
const app = express()

app.use(
  // [
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      connectSrc: ["'self'", 'https://checkout.stripe.com'],
      frameSrc: ["'self'", 'https://checkout.stripe.com'],
      childSrc: ["'self'", 'https://checkout.stripe.com'],
      scriptSrc: ["'self'", 'https://checkout.stripe.com'],
      styleSrc: [
        "'self'",
        'https://fonts.googleapis.com',
        'https://checkout.stripe.com',
      ],
      fontSrc: ["'self'", 'https://fonts.gstatic.com'],
      imgSrc: ["'self'", 'https://*.stripe.com', 'https://res.cloudinary.com'],
      baseUri: ["'self'"],
    },
  })
  // ]
)

This works for Google Fonts, images from Cloudinary and Stripe Checkout. If you use Stripe.js, replace https://checkout.stripe.com with the values found on the official documentation page.

When you allow self, you’re telling the browser that you allow loading resources from the same origin. That works because Heroku deploys your resources at the Heroku url. For example, your React app is at https://<your-heroku-app>.herokuapp.com/static/js/main.<some-random-string>.chunk.js.

I found the script on GitHub and adjusted it to my needs.

Recap

You’ve now learned how to work with the Content-Security-Policy for a MERN stack app. You have to add a few configuration options in your server-side code. That’s it!

Further Reading


  1. CSP ↩︎