title: NodeJS csrf protection gives ForbiddenError invalid csrf token only on one POST request form
body: <p>I have been unsuccessfully trying to find a solution on Google for the past several hours for the following issue:</p>
  
  <p>I have csurf set up and working well. It works for POST requests related to signing up/in users. I am trying to create a form in the user profile, that updates the user's data, but when I hit submit, I get <code>ForbiddenError: invalid csrf token</code>. </p>
  
  <p>On further testing, the csrt token is created on the profile page, but for some reason, it is invalid.</p>
  
  <p>(I have only recently picked up programming, I'm willing to provide additional information if I have missed something.)</p>
  
  <p>Tools used: </p>
  
  <ul>
  <li>Node.js v10.16.3</li>
  <li>Express v4.17.1</li>
  <li>ejs v2.7.1</li>
  <li>csurf v1.10.0</li>
  <li>Express session v1.16.2</li>
  <li>Passport v^0.4.0</li>
  <li>cookie-parser 1.4.4</li>
  <li>body-parser v1.19.0</li>
  </ul>
  
  <p>My app.js</p>
  
  <pre><code>let express = require("express"),
  app = express(),
  bodyParser = require("body-parser"),
  cookieParser = require('cookie-parser'),
  session = require("express-session"),
  mongoose = require("mongoose"),
  passport = require("passport"),
  flash = require('connect-flash'),
  validator = require('express-validator'),
  LocalStrategy = require("passport-local"),
  csrf = require('csurf'),
  csrfProtection = csrf({ cookie: true }),
  MongoStore = require('connect-mongo')(session);
  
  let indexRoutes = require('./routes/index');
  let userRoutes = require('./routes/user');
  let User = require("./models/user");
  
  // APP CONFIGURATION
  mongoose.connect("mongodb://localhost:27017/azax", { useNewUrlParser: true, useUnifiedTopology: true, }).then(() =&gt; {
      console.log("Connected to MongoDB");
  }).catch((error) =&gt; {
      console.log("Something is wrong...");
  });
  
  
  require('./config/passport');
  
  // View engine setup
  app.set("view engine", "ejs");
  app.use(express.static(__dirname + "/public"));
  
  // Initial setup
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));
  app.use(validator());
  
  // Session setup
  app.use(cookieParser());
  app.use(session({
      secret: 'somesecretforbytox',
      resave: false,
      saveUninitialized: false
  }));
  app.use(flash());
  
  // Initialize passport
  app.use(passport.initialize());
  app.use(passport.session());
  app.use(csrf());
  
  // CSRF
  app.use(function (req, res, next) {
      var token = req.csrfToken();
      res.cookie('XSRF-TOKEN', token);
      res.locals.csrfToken = token;
      next();
  });
  
  app.use(function (req, res, next) {
      res.locals.currentUser = req.user;
      res.locals.session = req.session;
      next();
  });
  
  // ======================
  // Connect to route files
  // ======================
  app.use('/user', userRoutes);
  app.use(indexRoutes);
  
  app.listen(3033, function () {
      console.log("Listening at port 3033...");
  });
  </code></pre>
  
  <p>My passport.js:</p>
  
  <pre><code>let passport = require('passport');
  let User = require('../models/user');
  let LocalStrategy = require('passport-local').Strategy;
  
  passport.serializeUser(function (user, done) {
    done(null, user.id);
  });
  
  passport.deserializeUser(function (id, done) {
    User.findById(id, function (err, user) {
      done(err, user);
    });
  });
  
  passport.use('local-signup', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
  }, function (req, email, password, done) {
    req.checkBody('username', 'Invalid username').notEmpty();
    req.checkBody('email', 'Invalid email').notEmpty().isEmail();
    req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
    let errors = req.validationErrors();
    if (errors) {
      let messages = [];
      errors.forEach(function (error) {
        messages.push(error.msg);
      });
      return done(null, false, req.flash('error', messages));
    }
    User.findOne({ 'email': email }, function (err, user) {
      if (err) {
        return done(err);
      }
      if (user) {
        return done(null, false, { message: 'Вече има акаунт с този имейл.' })
      }
      let username = req.body.username;
      let newUser = new User();
      newUser.username = username;
      newUser.email = email;
      newUser.password = newUser.encryptPassword(password);
      newUser.country = 'България';
      newUser.save(function (err, result) {
        if (err) {
          return done(err);
        }
        return done(null, newUser);
      });
    });
  }));
  
  passport.use('local-signin', new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
  }, function (req, email, password, done) {
    // req.checkBody('username', 'Invalid username').notEmpty();
    req.checkBody('email', 'Invalid email').notEmpty();
    req.checkBody('password', 'Invalid password').notEmpty();
    let errors = req.validationErrors();
    if (errors) {
      let messages = [];
      errors.forEach(function (error) {
        messages.push(error.msg);
      });
      return done(null, false, req.flash('error', messages));
    }
    User.findOne({ 'email': email }, function (err, user) {
      if (err) {
        return done(err);
      }
      if (!user) {
        return done(null, false, { message: 'Акаунтът не е намерен.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Грешна парола.' });
      }
      return done(null, user);
    });
  }));
  </code></pre>
  
  <p>HTML...:</p>
  
  <pre><code>&lt;form action="/user/profile" method="POST" class="form-validate form-horizontal" enctype="multipart/form-data"&gt;
      &lt;fieldset&gt;
          &lt;legend&gt;Edit address&lt;/legend&gt;
          &lt;!-- email --&gt;
          &lt;div class="control-group"&gt;
              &lt;div class="control-label"&gt;
                  &lt;label id="jform_email1-lbl" for="jform_email" class="hasPopover required" title="" data-content="Enter new email address." data-original-title="Email Address"&gt;
                      Email&lt;span class="star"&gt;&amp;nbsp;*&lt;/span&gt;&lt;/label&gt;
              &lt;/div&gt;
              &lt;div class="controls"&gt;
                  &lt;input type="email" name="email" class="validate-email required" id="jform_email" value="&lt;%= (typeof currentUser.email != 'undefined' ? currentUser.email : '') %&gt;" size="30" autocomplete="email" required aria-required="true"&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          &lt;!-- name --&gt;
          &lt;div class="control-group"&gt;
              &lt;div class="control-label"&gt;
                  &lt;label id="jform_fname-lbl" for="jform_fname" class="hasPopover required" title="" data-content="Enter new name." data-original-title="Name"&gt;
                      Name&lt;span class="star"&gt;&amp;nbsp;*&lt;/span&gt;&lt;/label&gt;
              &lt;/div&gt;
              &lt;div class="controls"&gt;
                  &lt;input type="text" name="firstName" id="jform_fname" value="&lt;%= (typeof currentUser.firstName != 'undefined' ? currentUser.firstName : '') %&gt;" class="required" size="30" required aria-required="true"&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/fieldset&gt;
  
      &lt;div class="form-actions"&gt;
          &lt;input type="hidden" name="_csrf" value="&lt;%= csrfToken %&gt;"&gt;
          &lt;button type="submit" class="btn btn-primary validate"&gt;
              &lt;span&gt;Save&lt;/span&gt;
          &lt;/button&gt;
          &lt;a class="btn" href="/" title="Cancel"&gt;Cancel&lt;/a&gt;
      &lt;/div&gt;
  &lt;/form&gt;
  </code></pre>
  
  <p>user.js:</p>
  
  <pre><code>let express = require('express'),
      router = express.Router(),
      csrf = require('csurf'),
      csrfProtection = csrf(),
      passport = require('passport');
  
  router.use(csrfProtection);
  let User = require("../models/user");
  
  // user profile
  router.get("/profile", isLoggedIn, csrfProtection, function (req, res) {
      res.render("user/profile", { csrfToken: req.csrfToken(), currentUser: req.user });
  });
  
  router.post('/profile', (req, res) =&gt; {
      updateRecord(req, res);
      res.redirect('/profile');
  });
  // update user data
  function updateRecord(req, res) {
      User.findOne({ _id: req.user.id }, (err, doc) =&gt; {
          doc.name = req.body.name;
          doc.save(function (err, doc) {
          });
      });
  }
  router.get("/profile/edit", isLoggedIn, csrfProtection, function (req, res) {
       res.render("user/edit", { csrfToken: req.csrfToken(), currentUser: req.user });
  });
  
  // sign up form works with csrf
  
  // signup form
  router.get("/signup", csrfProtection, function (req, res) {
      let messages = req.flash('error');
      res.render("user/signup", { csrfToken: req.csrfToken(), messages: messages, hasErrors: messages.length &gt; 0 });
  });
  
  // ... more routes
  
      module.exports = router;
  
  // middleware
  function isLoggedIn(req, res, next) {
      if (req.isAuthenticated()) {
          return next();
      }
      res.redirect('/user/login');
  }
  </code></pre>