sfarzoso
sfarzoso

Reputation: 1610

invalid csrf token when using ajax

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
});

Upvotes: 4

Views: 1376

Answers (2)

Abhishek Singh
Abhishek Singh

Reputation: 2727

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 }
}));

Upvotes: 2

Lord Elrond
Lord Elrond

Reputation: 16052

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.

Upvotes: 1

Related Questions