How I fixed Ajax Request to external resource errors (CSP) inside Discourse

If you are having trouble with an AJAX request and think the error might be due to the strict-origin-when-cross-origin Content Security Policy (CSP) directive, there are a few things you can try to fix the issue (observe those in the error console of Chrome Devtools):

  1. Make sure the server is configured to include the Access-Control-Allow-Origin header in the response to the preflight request as well as the actual AJAX request. This header allows the resource to be accessed from the specified origin.

Here is an example of how you can configure the Access-Control-Allow-Origin header in a Node.js server using the cors library:

const cors = require('cors');

app.use(cors({
  origin: 'http://example.com',
  optionsSuccessStatus: 200
}));

Alternatively, you can include the Access-Control-Allow-Origin header directly in your server-side code. For example, in a Node.js server, you can set the header like this:

res.setHeader('Access-Control-Allow-Origin', '*');
  1. Make sure the server is configured to allow the headers that are being used in the preflight request and the actual AJAX request. This can be done by including these headers in the Access-Control-Allow-Headers header.

Here is an example of how you can configure the Access-Control-Allow-Headers header in a Node.js server:

const http = require('http');

const server = http.createServer((req, res) => {
    
    res.setHeader('Access-Control-Allow-Origin', '*'); // Add this line to allow the resource to be accessed from any origin
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS'); // Add this line to allow the specified HTTP methods to be used
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, discourse-present, discourse-logged-in, discourse-track-view'); // Add this line to allow the specified headers to be used

    if (req.url === '/getTopicLikes') {
        console.log('Request received');
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ likes: 100 }));
    } else {
        res.writeHead(404);
        res.end();
    }
});

server.listen(3000, () => {
    console.log('Server started on port 3000');
});

process.on('SIGINT', () => {
    console.log('Shutting down the server');
    server.close();
});

Please note the two additional allow headers that are Discourse specific:
discourse-present, discourse-logged-in, discourse-track-view

I hope these steps help fix the issue with your AJAX request. Let me know if you have any questions.

4 Likes