Script Valley
Authentication From Scratch
Session-Based AuthenticationLesson 2.4

Building login and logout routes with sessions

login route, credential verification, session creation, logout route, session destroy, protected route middleware, req.session.userId

Login Route

// POST /auth/login
app.post('/auth/login', async (req, res) => {
  const { email, password } = req.body;
  const user = await db.findUserByEmail(email);

  if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }

  req.session.regenerate((err) => {
    if (err) return res.status(500).json({ error: 'Session error' });
    req.session.userId = user.id;
    res.json({ message: 'Logged in' });
  });
});

Logout Route

// POST /auth/logout
app.post('/auth/logout', (req, res) => {
  req.session.destroy((err) => {
    if (err) return res.status(500).json({ error: 'Could not log out' });
    res.clearCookie('connect.sid');
    res.json({ message: 'Logged out' });
  });
});

Protected Route Middleware

function requireAuth(req, res, next) {
  if (!req.session.userId) {
    return res.status(401).json({ error: 'Not authenticated' });
  }
  next();
}

app.get('/dashboard', requireAuth, (req, res) => {
  res.json({ userId: req.session.userId });
});

Always return the same error message for wrong email and wrong password. Different messages allow user enumeration โ€” an attacker can tell which emails exist in your system.

Up next

How to implement a remember me feature

Sign in to track progress

Building login and logout routes with sessions โ€” Session-Based Authentication โ€” Authentication From Scratch โ€” Script Valley โ€” Script Valley