I've recently been trying to setup NodeBB on my server, but whenever i try to login or register the POST request returns a 403 forbidden response and NodeBB logs an "invalid csrf token" error.
The following software packages are used:
NodeBB 1.10.1
MongoDB 3.2.11
Node.js 8.11.4
Debian 9.3
NodeBB itself is a subfolder installation in https://endless-endeavors.theswc.net/forum/. The node server is multi-tenant and works with express.js as a router/reverse proxy. All external http requests are redirected to https, but requests to the nodeBB server are proxied internally over http. Essentially this is the flow for an incoming forum request:
main server app -> enforce https, direct request to endless-endeavors.theswc.net directory
host/domain app -> Check url, if /forum, proxy to port 4567 over http (or wss if websocket)
let nodeBB do its thing.
I've been googling and have found quite a few threads, but none of the suggested solutions have worked. things i have tried so far:
Check url in config.json: 'https://endless-endeavors.theswc.net/forum/'
Make sure cookieDomain is '' in MongoDB
Including header 'X-Forwarded-Proto: https'
Including header 'X-Forwarded-SSL: on'
Including header 'X-Url-Scheme: https'
I've also found that in the GET request for the login form, no X-CSRF-Token header is received. The form itself however is populated with a token.
Lastly, here are the relevant code snippets:
main server app
#!/usr/bin/env nodejs
// filename: app.js
const http = require('http');
const https = require('https');
const fs = require('fs');
const express = require('express');
const vhost = require('vhost');
const app = express();
const sslOptions = {
cert: fs.readFileSync('./.sslcert/fullchain.pem'),
key: fs.readFileSync('./.sslcert/privkey.pem')
}
http.createServer(function(req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
app
.use(require('helmet')())
.use(express.static(__dirname + '/static'))
<redacted, other domains>
.use(vhost('endless-endeavors.theswc.net', require('./apps/EndlessEndeavors').app))
app.get('/', function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('');
});
domain app
const express = require('express')
const app = express();
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer();
app.use('/static',express.static(__dirname + '/static'));
app.use('', express.static(__dirname + '/dist/EndlessEndeavors'));
app.all('/forum[/]+*', function(req, res){
if(req.url.substr(0,18).indexOf('socket.io')>-1){
console.log('got socket request');
proxy.web(req, res, {target: 'wss://endless-endeavors.theswc.net:4567', ws: true});
} else {
res.header('X-Forwarded-Proto','https');
res.header('X-Forwarded-Ssl','on');
res.header('X-Url-Scheme','https');
res.header('Access-Control-Allow-Origin','endless-endeavors.theswc.net');
proxy.web(req, res, {target: 'http://endless-endeavors.theswc.net:4567'});
}
});
app.all('/forum$', function(req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + '/forum/' });
res.end();
}
)
exports.app = app;
nodeBB config.json
{
"url": "https://endless-endeavors.theswc.net/forum/",
"secret": "<redacted>",
"database": "mongo",
"port": 4567,
"mongo": {
"host": "127.0.0.1",
"port": 27017,
"username": "<redacted>",
"password": "<redacted>",
"database": "<redacted>",
"uri": "<redacted>"
}
}
Hopefully this is enough into to help find the cause of the invalid csrf token issue... i have no idea what else could be wrong at this point.