1
votes

I'm just getting into MEAN-stack/general Nodejs stuff recently after years of PHP/MySQL web development and I'm looking at authentication. I used this guide to create a simple authentication server with Passport and json-server. It works exactly as described in that guide.

However, I want to be using mongoose/MongoDB for the project I'm learning with so I decided to try and alter the code in that guide to work for mongoose.

All seemed to be going fine (the '/authrequired' endpoint can't be hit without having a cookie that matches a session on the ExpressJS server and login functionality works) but I tried adding registering functionality and I'm getting a renaming error I've never seen before and can't find much information on in this context.

The registering code works fine from mongoose's point-of-view but when I try and call req.login() which should set the session using passport and redirect to '/authrequired' (which is a guarded area requiring a session), I get kicked back to '/' (which is what happens when '/authrequired' can't authenticate the user).

The error I get is:

Error: EPERM: operation not permitted, rename 'C:\Users\admin\express-auth\server\sessions\39cad5de-5e1b-4319-b967-c77dd3ef729d.json.4139658133' -> 'C:\Users\admin\express-auth\server\sessions\39cad5de-5e1b-4319-b967-c77dd3ef729d.json'

I don't understand why express is trying to rename the session file in the first place. If I look in the sessions folder there are 2 files:

  • 39cad5de-5e1b-4319-b967-c77dd3ef729d.json
  • 39cad5de-5e1b-4319-b967-c77dd3ef729d.json.4139658133

The first has the json session data, the second one is blank.

Does anyone know what is going on? What have I done wrong and what can I do to resolve this?

I was not getting this renaming error using the json-server/axios version described in the linked guide.

Thanks

Passport Configuration

passport.use(new LocalStrategy(
  { usernameField: 'email' },
  (email, password, done) => {
    User.findOne({email: email}, (err, user) => {
      if(!user) {
        return done(null, false, { message: 'Invalid credentials.\n' });
      }
      if(!bcrypt.compareSync(password, user.password)) {
        return done(null, false, { message: 'Invalid credentials.\n' });
      }
      return done(null, user);
    });
  }
});

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
    if(user) {
      done(null, user);
    }
    else if(err) {
      done(error, false);
    }
  });
});

app setup

// create the server
const app = express();

// add & configure middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(session({
  genid: (req) => {
    return uuid() // use UUIDs for session IDs
  },
  store: new FileStore(),
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());

Register endpoint

app.post('/register', (req, res, next) => { 
  User.findOne({email: req.body.email}, (err, user) => {
    if(user) {
      res.send('Account with email already exists.');
    } else {
      console.log(req.body.password);
      bcrypt.hash(req.body.password, null, null, (err, hash) => {
        if(err) { return next(err); }
        var newUser = new User({
          username: req.body.username,
          email: req.body.email,
          password: hash,
          passwordConf: hash
        });
        newUser.save((err, savedUser) => {
          console.log(savedUser);
          if(err) {
            return res.send('error saving user.');
          }
          else {
            req.login(savedUser, (err) => {
              if(err) { return next(err); }
              return res.redirect('/authrequired');
            });
          }
        });
      });
    }
  });
});

Login endpoint

    app.post('/login', (req, res, next) => {
  passport.authenticate('local', (err, user, info) => {
    if(info) {return res.send(info.message)}
    if (err) { return next(err); }
    if (!user) { return res.redirect('/login'); }
    req.login(user, (err) => {
      if (err) { return next(err); }
      return res.redirect('/authrequired');
    });
  })(req, res, next);
});

Authrequired endpoint

app.get('/authrequired', (req, res) => {
  if(req.isAuthenticated()) {
    res.send('you hit the authentication endpoint\n')
  } else {
    res.redirect('/')
  }
});
1
This is a permission related issue, I am not sure but you can do one thing: just run the command prompt as administrator or if you are using Mac or Linux just use sudo with your command, I hope it can help.Arpit Kumar
Hmm I thought I was running it as administrator, I'll make sure and have a go when I get home thanks. Do you have any idea why it is trying to rename the session file in the first place?poncho
@ArpitMeena Thanks it works now!poncho

1 Answers

0
votes

I was facing a similar issue. I realized that both of us had session declared twice.

app.use(session({
  genid: (req) => {
    return uuid() // use UUIDs for session IDs
  },
  store: new FileStore(),
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))
app.use(passport.initialize());
app.use(passport.session());

The error disappeared when I removed the first session declaration.

app.use(session({
  genid: (req) => {
    return uuid() // use UUIDs for session IDs
  },
  store: new FileStore(),
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))