4

I started learning NodeJs and pushed by my knowledge of js I start writing some code for create the user registration logic.

Essentially I have configured ExpressJS in the following way:

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const session = require('express-session');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');

app.use(session({
    secret: 'foofofoo',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: true }
}));

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(csrf());
app.use(function (req, res, next) {
    var csrfToken = req.csrfToken();
    res.cookie('XSRF-TOKEN', csrfToken);
    res.locals.csrfToken = csrfToken;
    next();
});

then I created a basic .ejs view for the user registration:

<meta name="csrf-token" content="<%= csrfToken %>">
<p>
    <label class="w3-text-blue"><b>User Name</b></label>
    <input class="w3-input w3-border" id="uname" name="uname" type="text"></p>
<p>
    <label class="w3-text-blue"><b>Password</b></label>
    <input class="w3-input w3-border" id="upass" name="pass" type="text"></p>
<p>
    <button class="w3-btn w3-blue" id="regForm">Register</button></p>

the csrfToken is taken by the middleware above. When the user press the button regForm this code is called:

$("#regForm").click(function () {
    let uname = $("#uname").val();
    let upass = $("#upass").val();
    let token  = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    let regData = 
    {
        'name': uname, 
        'pass': upass 
    };

    $.ajax({
        type: 'POST',
        url: '/registerUser',
        headers: {"X-CSRF-Token": token },
        data: regData,
        success: function (data) {
            $("#mainDiv").html(data);
        }
    });
});

and looking at the ajax request the token is passed correctly:

enter image description here

but inside the console I get:

ForbiddenError: invalid csrf token

this is the route method:

app.post('/registerUser', function(req, res, next){
    //todo
});
Lord Elrond
  • 13,430
  • 7
  • 40
  • 80
sfarzoso
  • 1,356
  • 2
  • 24
  • 65

2 Answers2

2

First of all kudos to you, as you have started working on nodejs and trying these stuff by yourself.

There is no need to change the structure or the code itself as it is written correctly. There is only one mistake which is causing the issue and it is in your csrf initialization. Kindly add the cookie parameter in your csrf initialization as shown below:

app.use(csrf({ cookie: true }));

Also, always use a session store in your application. Below is an example to use the express session as your session store:

var session        = require('express-session');
var MemoryStore    = require('session-memory-store')(session);

app.use(session({
    store : new MemoryStore({ expires : 86400, checkperiod : 1800}),
    secret: 'foofofoo',
    resave: false,
    saveUninitialized: true,
    cookie: { secure: true }
}));
Abhishek Singh
  • 2,642
  • 15
  • 24
1

From the csurf docs:

Inside the view, set the csrfToken value as the value of a hidden input field named _csrf

First, change this:

<meta name="csrf-token" content="<%= csrfToken %>">

to this:

<input type="hidden" name="_csrf" value="<%= csrfToken %>" id="csrf">

Then on your jQuery page change this:

let token  = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
{
    'name': uname, 
    'pass': upass 
};

to this:

let token  = $('#csrf').val();
{
    'name': uname, 
    'pass': upass,
    '_csrf':token
};

If you are still having issues let me know what happens when you try this.

PS: this question was a pretty good reference for your problem.

Lord Elrond
  • 13,430
  • 7
  • 40
  • 80