Building a Node.js Server with Basic Authentication Using Express.js

This tutorial shows how to create a Node.js server with Express.js in JavaScript, implementing Basic Authentication to secure a /user endpoint. The server authenticates users against a userlist.json file, supports CORS for an Angular client at localhost:4200, and mimics the functionality of a TypeScript HTTP server. Perfect for learning Express and authentication!

Prerequisites

  • Node.js (LTS, e.g., 20.x): Install from nodejs.org and verify:node -v npm -v
  • Text editor: VS Code or IntelliJ.
  • Terminal: For commands.
  • Angular client (optional): Running at http://localhost:4200 (see Angular tutorial).

Step 1: Set Up the Project

Create a project folder and initialize it:

mkdir nodejs-express-auth
cd nodejs-express-auth
npm init -y

Install Express.js:

npm install express

Step 2: Create the User List

Create userlist.json in the project root:

[
  {
    "username": "admin",
    "password": "password123",
    "role": "admin"
  },
  {
    "username": "user",
    "password": "secret",
    "role": "user"
  }
]

Step 3: Write the Server Code

Create server.js:

const express = require('express');
const fs = require('fs');
const path = require('path');£
const express = require('express');
const fs = require('fs');
const path = require('path');£

const app = express();
const userListPath = path.join(__dirname, 'userlist.json');

// Middleware for CORS
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
  next();
});

// Handle OPTIONS preflight
app.options('*', (req, res) => {
  res.status(204).end();
});

// Authentication middleware
const authenticate = (req, res, next) => {
  const authHeader = req.headers.authorization;

  if (!authHeader) {
    res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
    return res.status(401).send('Authentication required');
  }

  const base64Credentials = authHeader.split(' ')[1];
  const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
  const [username, password] = credentials.split(':');

  let users = [];
  try {
    const data = fs.readFileSync(userListPath, 'utf8');
    users = JSON.parse(data);
  } catch (err) {
    console.error('Error reading userlist.json:', err);
    return res.status(500).send('Server error');
  }

  const user = users.find(u => u.username === username && u.password === password);
  if (!user) {
    res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
    return res.status(401).send('Invalid credentials');
  }

  req.user = { username: user.username, role: user.role };
  next();
};

// Routes
app.get('/user', authenticate, (req, res) => {
  res.json({ username: req.user.username, role: req.user.role });
});

app.get('/', (req, res) => {
  res.send('Public page: Hello World');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}/`);
});

What’s Happening?

  • Express: Simplifies routing and middleware compared to raw HTTP.
  • CORS: Allows Angular at localhost:4200 to connect.
  • Authentication: Checks Authorization header (Basic <Base64(username:password)>) against userlist.json.
  • Routes:
    • /user: Protected, returns { username, role }.
    • /: Public, returns “Hello World”.
  • Preflight: Handles OPTIONS requests for CORS.

Step 4: Run the Server

Start the server:

node server.js

See: Server running at http://localhost:3000/.

Step 5: Test the Server

  • Browser:
    • Visit http://localhost:3000/ → “Public page: Hello World”.
    • Visit http://localhost:3000/user → Enter admin:password123 → {“username”:”admin”,”role”:”admin”}. Wrong credentials show “Invalid credentials”.
  • cURL:curl http://localhost:3000 # Public: "Public page: Hello World" curl -u admin:password123 http://localhost:3000/user # Secure: {"username":"admin","role":"admin"} curl http://localhost:3000/user # No auth: "Authentication required"

Security Notes

  • JSON File: Replace with a database (e.g., PostgreSQL) in production.
  • HTTPS: Use HTTPS to secure Basic Auth credentials.
  • Error Handling: Add robust validation for userlist.json.
  • Rate Limiting: Use express-rate-limit to prevent brute-force attacks.

 

Leave a Reply