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.