Contents

Authentication and Security in Node.js

When building a web application, making sure users can securely log in and keeping sensitive information safe is crucial. This guide will walk you through the basics of authentication in Node.js, how to set up user authentication with Passport.js, securing your app with environment variables and bcrypt, and using JSON Web Tokens (JWT) for authentication.

Understanding Authentication in Node.js

Authentication is all about verifying who a user is. In a web app, this usually means the user provides a username and password, and you check these against what’s stored in your system.

There are a few common ways to handle authentication:

  • Session-Based Authentication: The server creates a session for the user and stores the session ID in a cookie. This session ID is used to track the user’s requests.
  • Token-Based Authentication: The server gives the user a token (like a JWT) after they log in. This token is stored on the client side and sent with every request to confirm the user’s identity.
  • OAuth and OpenID Connect: These are standard protocols that allow users to log in with third-party services like Google or Facebook.

Setting Up User Authentication with Passport.js

Passport.js is a popular tool in Node.js for handling user authentication. It supports various strategies, like logging in with a username/password, OAuth, and more.

  • 1.  Install Passport.js and Dependencies
    First, you need to install Passport.js along with the local strategy for handling username/password authentication.
				
					npm install passport passport-local express-session

				
			
  • 2.  Set Up Passport.js in Your App
    Configure Passport.js to use a local strategy and manage user sessions.
				
					const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bcrypt = require('bcrypt');

// Mock user database
const users = [
  { id: 1, username: 'user1', passwordHash: bcrypt.hashSync('password1', 10) },
  { id: 2, username: 'user2', passwordHash: bcrypt.hashSync('password2', 10) }
];

// Passport local strategy
passport.use(new LocalStrategy((username, password, done) => {
  const user = users.find(u => u.username === username);
  if (!user) return done(null, false, { message: 'Incorrect username.' });
  if (!bcrypt.compareSync(password, user.passwordHash)) return done(null, false, { message: 'Incorrect password.' });
  return done(null, user);
}));

passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => {
  const user = users.find(u => u.id === id);
  done(null, user);
});

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(session({ secret: 'secret', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());

// Routes
app.post('/login', passport.authenticate('local', {
  successRedirect: '/dashboard',
  failureRedirect: '/login',
}));

app.get('/dashboard', (req, res) => {
  if (req.isAuthenticated()) res.send('Welcome to your dashboard!');
  else res.redirect('/login');
});

app.get('/login', (req, res) => {
  res.send('<form action="/login" method="post"><input type="text" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><button type="submit">Login</button></form>');
});

app.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/login');
});

app.listen(3000, () => console.log(`Server running on http://localhost:3000`));

				
			

Securing Your Application with Environment Variables and bcrypt

Sensitive information, like database credentials or secret keys, shouldn’t be hardcoded in your app. Instead, store these in environment variables.

  • 1.  Set Up Environment Variables
    Use the dotenv package to load environment variables from a .env file.

				
					npm install dotenv


				
			

Create a .env file:

				
					SECRET_KEY=your-secret-key
DB_USER=your-db-user
DB_PASS=your-db-pass


				
			

Load these variables in your app:

				
					require('dotenv').config();
const secretKey = process.env.SECRET_KEY;


				
			
  • 2.  Use bcrypt for Password Hashing
    Hash passwords before storing them to protect user data.
				
					const bcrypt = require('bcrypt');
const saltRounds = 10;
const plainPassword = 'mysecretpassword';

bcrypt.hash(plainPassword, saltRounds, (err, hash) => {
  if (err) throw err;
  console.log('Hashed password:', hash);
});


				
			

To compare a password:

				
					const enteredPassword = 'mysecretpassword';
const storedHash = 'stored-hashed-password-from-db';

bcrypt.compare(enteredPassword, storedHash, (err, result) => {
  if (err) throw err;
  console.log(result ? 'Password matches!' : 'Password does not match.');
});

				
			

Introduction to JWT (JSON Web Tokens) for Authentication

JWTs are a popular way to handle authentication in web apps. They’re compact, URL-safe tokens that represent user information.

  • 1.  Install the jsonwebtoken Package

				
					npm install jsonwebtoken

				
			
  • 2.  Generate a JWT
    When a user logs in, create a JWT and send it back to the client.
				
					const jwt = require('jsonwebtoken');
const user = { id: 1, username: 'johndoe' };
const token = jwt.sign(user, 'your-secret-key', { expiresIn: '1h' });
console.log('Generated JWT:', token);


				
			
  • 3.  Verify a JWT
    For protected routes, verify the JWT to ensure the user is authenticated.
				
					function authenticateToken(req, res, next) {
  const token = req.headers['authorization'];
  if (!token) return res.sendStatus(401);

  jwt.verify(token, 'your-secret-key', (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
}

app.get('/dashboard', authenticateToken, (req, res) => {
  res.send('Welcome to the protected dashboard!');
});


				
			

Conclusion

Authentication and security are crucial for any web application. With Node.js, tools like Passport.js, bcrypt, environment variables, and JWTs give you the building blocks to create a secure, reliable authentication system. By mastering these techniques, you can keep your app and users’ data safe from threats.