Set up secure JWT authentication for Node.js applications with Redis session storage, security middleware, and production-ready hardening practices.
Prerequisites
- Root or sudo access
- Node.js 18+ installed
- Redis server access
- Basic JavaScript knowledge
- Understanding of HTTP and REST APIs
What this solves
This tutorial helps you implement JWT (JSON Web Token) authentication in Node.js applications with Redis for session storage. You'll learn to create secure authentication middleware, configure Redis for session management, and apply security hardening techniques to protect against common attack vectors like token hijacking, session fixation, and brute force attacks.
Step-by-step installation
Update system packages and install Node.js
Start by updating your package manager and installing Node.js with npm package manager.
sudo apt update && sudo apt upgrade -y
sudo apt install -y nodejs npm curl
Install and configure Redis
Install Redis server for session storage and configure it with security settings.
sudo apt install -y redis-server
Configure Redis security settings
Modify Redis configuration to enable authentication and bind to localhost only for security.
# Bind to localhost only
bind 127.0.0.1 ::1
Set authentication password
requirepass your_secure_redis_password_here_2024
Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
Set memory limit and policy
maxmemory 256mb
maxmemory-policy allkeys-lru
Start Redis service
Enable and start Redis service to run on system boot.
sudo systemctl enable --now redis-server
sudo systemctl status redis-server
Create Node.js project structure
Set up a new Node.js project directory with proper permissions and initialize package.json.
mkdir -p /opt/nodejs-auth-app
cd /opt/nodejs-auth-app
sudo chown $USER:$USER /opt/nodejs-auth-app
npm init -y
Install required Node.js packages
Install Express.js, JWT libraries, Redis client, and security middleware packages.
npm install express jsonwebtoken bcryptjs redis express-rate-limit helmet cors express-validator morgan dotenv connect-redis express-session
Create environment configuration
Set up environment variables for JWT secrets, Redis connection, and security settings.
# JWT Configuration
JWT_SECRET=your_jwt_secret_key_minimum_32_characters_2024
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=your_jwt_refresh_secret_minimum_32_characters_2024
JWT_REFRESH_EXPIRES_IN=7d
Redis Configuration
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=your_secure_redis_password_here_2024
Session Configuration
SESSION_SECRET=your_session_secret_minimum_32_characters_2024
SESSION_MAX_AGE=900000
Application Configuration
PORT=3000
NODE_ENV=production
Create Redis connection module
Set up Redis client with authentication and connection pooling for session storage.
const redis = require('redis');
const { promisify } = require('util');
const client = redis.createClient({
host: process.env.REDIS_HOST || '127.0.0.1',
port: process.env.REDIS_PORT || 6379,
password: process.env.REDIS_PASSWORD,
retry_strategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
}
});
client.on('error', (err) => {
console.error('Redis Client Error:', err);
});
client.on('connect', () => {
console.log('Connected to Redis');
});
// Promisify Redis methods
const getAsync = promisify(client.get).bind(client);
const setAsync = promisify(client.set).bind(client);
const delAsync = promisify(client.del).bind(client);
const existsAsync = promisify(client.exists).bind(client);
module.exports = {
client,
getAsync,
setAsync,
delAsync,
existsAsync
};
Create JWT utility module
Implement JWT token generation, verification, and refresh token functionality with security best practices.
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const { setAsync, getAsync, delAsync } = require('../config/redis');
class JWTManager {
static generateTokens(payload) {
const accessToken = jwt.sign(
payload,
process.env.JWT_SECRET,
{
expiresIn: process.env.JWT_EXPIRES_IN,
issuer: 'nodejs-auth-app',
audience: 'api-users'
}
);
const refreshToken = jwt.sign(
{ userId: payload.userId },
process.env.JWT_REFRESH_SECRET,
{
expiresIn: process.env.JWT_REFRESH_EXPIRES_IN,
issuer: 'nodejs-auth-app'
}
);
return { accessToken, refreshToken };
}
static verifyAccessToken(token) {
return jwt.verify(token, process.env.JWT_SECRET, {
issuer: 'nodejs-auth-app',
audience: 'api-users'
});
}
static verifyRefreshToken(token) {
return jwt.verify(token, process.env.JWT_REFRESH_SECRET, {
issuer: 'nodejs-auth-app'
});
}
static async storeRefreshToken(userId, refreshToken) {
const key = refresh_token:${userId};
const hashedToken = crypto.createHash('sha256').update(refreshToken).digest('hex');
await setAsync(key, hashedToken, 'EX', 7 24 60 * 60); // 7 days
}
static async verifyStoredRefreshToken(userId, refreshToken) {
const key = refresh_token:${userId};
const storedHash = await getAsync(key);
const providedHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
return storedHash === providedHash;
}
static async revokeRefreshToken(userId) {
const key = refresh_token:${userId};
await delAsync(key);
}
}
module.exports = JWTManager;
Create authentication middleware
Implement JWT authentication middleware with rate limiting and security checks.
const JWTManager = require('../utils/jwt');
const rateLimit = require('express-rate-limit');
const { getAsync, setAsync } = require('../config/redis');
// Rate limiting for authentication attempts
const authLimiter = rateLimit({
windowMs: 15 60 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many authentication attempts, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
// JWT verification middleware
const authenticateToken = async (req, res, next) => {
try {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
// Check if token is blacklisted
const isBlacklisted = await getAsync(blacklist:${token});
if (isBlacklisted) {
return res.status(401).json({ error: 'Token has been revoked' });
}
const decoded = JWTManager.verifyAccessToken(token);
req.user = decoded;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
if (error.name === 'JsonWebTokenError') {
return res.status(401).json({ error: 'Invalid token' });
}
return res.status(500).json({ error: 'Authentication error' });
}
};
// Blacklist token on logout
const blacklistToken = async (token, expiresIn) => {
const key = blacklist:${token};
await setAsync(key, 'true', 'EX', expiresIn);
};
module.exports = {
authenticateToken,
authLimiter,
blacklistToken
};
Create session configuration
Configure Express sessions with Redis store and security settings for session management.
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const { client } = require('./redis');
const sessionConfig = {
store: new RedisStore({ client: client }),
secret: process.env.SESSION_SECRET,
name: 'sessionId',
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production', // HTTPS only in production
httpOnly: true, // Prevent XSS attacks
maxAge: parseInt(process.env.SESSION_MAX_AGE) || 900000, // 15 minutes
sameSite: 'strict' // CSRF protection
},
rolling: true // Reset expiration on activity
};
module.exports = sessionConfig;
Create main application file
Set up Express server with security middleware, authentication routes, and proper error handling.
require('dotenv').config();
const express = require('express');
const bcrypt = require('bcryptjs');
const helmet = require('helmet');
const cors = require('cors');
const morgan = require('morgan');
const session = require('express-session');
const { body, validationResult } = require('express-validator');
const JWTManager = require('./utils/jwt');
const { authenticateToken, authLimiter, blacklistToken } = require('./middleware/auth');
const sessionConfig = require('./config/session');
require('./config/redis'); // Initialize Redis connection
const app = express();
// Security middleware
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
scriptSrc: ["'self'"],
imgSrc: ["'self'", "data:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3001'],
credentials: true,
optionsSuccessStatus: 200
}));
app.use(morgan('combined'));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
app.use(session(sessionConfig));
// Mock user data (replace with database in production)
const users = new Map();
// Register endpoint
app.post('/api/register', [
body('username').isLength({ min: 3, max: 20 }).isAlphanumeric(),
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }).matches(/^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[@$!%?&])[A-Za-z\d@$!%?&]/)
], authLimiter, async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { username, email, password } = req.body;
if (users.has(email)) {
return res.status(409).json({ error: 'User already exists' });
}
const hashedPassword = await bcrypt.hash(password, 12);
const userId = Date.now().toString();
users.set(email, {
userId,
username,
email,
password: hashedPassword,
createdAt: new Date()
});
res.status(201).json({ message: 'User registered successfully', userId });
} catch (error) {
res.status(500).json({ error: 'Registration failed' });
}
});
// Login endpoint
app.post('/api/login', [
body('email').isEmail().normalizeEmail(),
body('password').notEmpty()
], authLimiter, async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { email, password } = req.body;
const user = users.get(email);
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const payload = {
userId: user.userId,
email: user.email,
username: user.username
};
const { accessToken, refreshToken } = JWTManager.generateTokens(payload);
await JWTManager.storeRefreshToken(user.userId, refreshToken);
// Store session data
req.session.userId = user.userId;
req.session.loginTime = new Date();
res.json({
message: 'Login successful',
accessToken,
refreshToken,
user: {
userId: user.userId,
username: user.username,
email: user.email
}
});
} catch (error) {
res.status(500).json({ error: 'Login failed' });
}
});
// Token refresh endpoint
app.post('/api/refresh', async (req, res) => {
try {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(401).json({ error: 'Refresh token required' });
}
const decoded = JWTManager.verifyRefreshToken(refreshToken);
const isValid = await JWTManager.verifyStoredRefreshToken(decoded.userId, refreshToken);
if (!isValid) {
return res.status(401).json({ error: 'Invalid refresh token' });
}
// Find user (replace with database query)
const user = Array.from(users.values()).find(u => u.userId === decoded.userId);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const payload = {
userId: user.userId,
email: user.email,
username: user.username
};
const { accessToken, refreshToken: newRefreshToken } = JWTManager.generateTokens(payload);
// Revoke old refresh token and store new one
await JWTManager.revokeRefreshToken(decoded.userId);
await JWTManager.storeRefreshToken(decoded.userId, newRefreshToken);
res.json({ accessToken, refreshToken: newRefreshToken });
} catch (error) {
res.status(401).json({ error: 'Token refresh failed' });
}
});
// Protected route example
app.get('/api/profile', authenticateToken, (req, res) => {
res.json({
message: 'Protected resource accessed',
user: req.user,
sessionId: req.session.id
});
});
// Logout endpoint
app.post('/api/logout', authenticateToken, async (req, res) => {
try {
const token = req.headers['authorization'].split(' ')[1];
const decoded = JWTManager.verifyAccessToken(token);
// Blacklist current token
await blacklistToken(token, 900); // 15 minutes
// Revoke refresh token
await JWTManager.revokeRefreshToken(decoded.userId);
// Destroy session
req.session.destroy((err) => {
if (err) {
console.error('Session destroy error:', err);
}
});
res.json({ message: 'Logout successful' });
} catch (error) {
res.status(500).json({ error: 'Logout failed' });
}
});
// Error handling middleware
app.use((error, req, res, next) => {
console.error('Application error:', error);
res.status(500).json({ error: 'Internal server error' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, '127.0.0.1', () => {
console.log(Server running on port ${PORT});
});
module.exports = app;
Create systemd service file
Set up systemd service to run the Node.js application with proper user permissions and security settings.
[Unit]
Description=Node.js JWT Authentication App
After=network.target redis.service
Requires=redis.service
[Service]
Type=simple
User=nodejs
Group=nodejs
WorkingDirectory=/opt/nodejs-auth-app
EnvironmentFile=/opt/nodejs-auth-app/.env
ExecStart=/usr/bin/node src/app.js
Restart=always
RestartSec=10
Security settings
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/nodejs-auth-app
Resource limits
LimitNOFILE=65536
LimitNPROC=4096
[Install]
WantedBy=multi-user.target
Create application user and set permissions
Create a dedicated user for running the Node.js application with minimal privileges.
sudo useradd --system --shell /bin/false --home-dir /opt/nodejs-auth-app nodejs
sudo chown -R nodejs:nodejs /opt/nodejs-auth-app
sudo chmod 755 /opt/nodejs-auth-app
sudo chmod 600 /opt/nodejs-auth-app/.env
Start and enable the application service
Enable the systemd service to start automatically and verify it's running correctly.
sudo systemctl daemon-reload
sudo systemctl enable --now nodejs-auth-app
sudo systemctl status nodejs-auth-app
Verify your setup
Test the authentication endpoints and verify Redis session storage is working correctly.
# Check service status
sudo systemctl status nodejs-auth-app
sudo systemctl status redis-server
Test registration
curl -X POST http://localhost:3000/api/register \
-H "Content-Type: application/json" \
-d '{"username":"testuser","email":"test@example.com","password":"SecurePass123!"}'
Test login
curl -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"SecurePass123!"}'
Check Redis sessions
redis-cli -a your_secure_redis_password_here_2024 KEYS "*"
Check application logs
sudo journalctl -u nodejs-auth-app -f
Security hardening configuration
Configure firewall rules
Set up firewall rules to restrict access to Redis and application ports.
# Install ufw if not already installed
sudo apt install -y ufw
Configure firewall rules
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 3000/tcp comment 'Node.js app'
Block Redis port from external access
sudo ufw deny 6379/tcp
Enable firewall
sudo ufw --force enable
sudo ufw status verbose
Configure log rotation
Set up log rotation for application logs to prevent disk space issues.
/var/log/nodejs-auth-app/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 nodejs nodejs
postrotate
systemctl reload nodejs-auth-app
endscript
}
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Redis connection failed | Authentication or binding issues | Check Redis password in /etc/redis/redis.conf and .env file |
| JWT verification fails | Clock skew or wrong secret | Sync system time with sudo ntpdate -s time.nist.gov |
| Session not persisting | Redis store configuration issue | Verify Redis connection and session config in application |
| Rate limiting not working | Missing client IP identification | Configure proper reverse proxy headers or trust proxy setting |
| CORS errors in browser | Origin not allowed | Add frontend domain to ALLOWED_ORIGINS in .env file |
| Service won't start | Port already in use | Check with sudo netstat -tlnp | grep :3000 and kill conflicting process |
Next steps
- Integrate Redis with microservices architecture for advanced caching patterns
- Setup NGINX reverse proxy with SSL for production deployment
- Configure Node.js application logging for better observability
- Implement OAuth2 integration with Passport.js for social login
- Setup Node.js microservices with Docker Compose for scalable architecture
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
APP_DIR="/opt/nodejs-auth-app"
APP_USER="nodeapp"
REDIS_PASSWORD=""
JWT_SECRET=""
JWT_REFRESH_SECRET=""
SESSION_SECRET=""
# Usage function
usage() {
echo "Usage: $0 [--app-dir PATH] [--user USERNAME]"
echo " --app-dir PATH Application directory (default: /opt/nodejs-auth-app)"
echo " --user USERNAME Application user (default: nodeapp)"
echo " -h, --help Show this help message"
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--app-dir)
APP_DIR="$2"
shift 2
;;
--user)
APP_USER="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
usage
;;
esac
done
# Cleanup function
cleanup() {
echo -e "${RED}Installation failed. Cleaning up...${NC}"
if id "$APP_USER" &>/dev/null; then
userdel -r "$APP_USER" 2>/dev/null || true
fi
rm -rf "$APP_DIR" 2>/dev/null || true
systemctl stop redis-server 2>/dev/null || true
systemctl disable redis-server 2>/dev/null || true
}
trap cleanup ERR
# Generate secure random passwords
generate_password() {
openssl rand -base64 48 | tr -d "=+/" | cut -c1-64
}
# Check prerequisites
echo -e "${BLUE}[1/12] Checking prerequisites...${NC}"
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root${NC}"
exit 1
fi
if ! command -v openssl &> /dev/null; then
echo -e "${RED}OpenSSL is required but not installed${NC}"
exit 1
fi
# Auto-detect distribution
echo -e "${BLUE}[2/12] Detecting distribution...${NC}"
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_SERVICE="redis-server"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_SERVICE="redis"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_SERVICE="redis"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
REDIS_CONFIG="/etc/redis.conf"
REDIS_SERVICE="redis"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
echo -e "${GREEN}Detected: $PRETTY_NAME${NC}"
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
# Update system packages
echo -e "${BLUE}[3/12] Updating system packages...${NC}"
$PKG_UPDATE
# Install Node.js and dependencies
echo -e "${BLUE}[4/12] Installing Node.js and dependencies...${NC}"
$PKG_INSTALL nodejs npm curl
# Verify Node.js installation
if ! command -v node &> /dev/null || ! command -v npm &> /dev/null; then
echo -e "${RED}Node.js installation failed${NC}"
exit 1
fi
echo -e "${GREEN}Node.js $(node --version) and npm $(npm --version) installed${NC}"
# Install Redis
echo -e "${BLUE}[5/12] Installing Redis...${NC}"
$PKG_INSTALL redis
# Generate secure passwords
echo -e "${BLUE}[6/12] Generating secure credentials...${NC}"
REDIS_PASSWORD=$(generate_password)
JWT_SECRET=$(generate_password)
JWT_REFRESH_SECRET=$(generate_password)
SESSION_SECRET=$(generate_password)
# Configure Redis
echo -e "${BLUE}[7/12] Configuring Redis...${NC}"
cp "$REDIS_CONFIG" "${REDIS_CONFIG}.backup"
cat > "$REDIS_CONFIG" << EOF
# Network
bind 127.0.0.1 ::1
port 6379
timeout 0
tcp-keepalive 300
# General
daemonize yes
supervised systemd
pidfile /var/run/redis/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-server.log
databases 16
# Security
requirepass $REDIS_PASSWORD
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
rename-command CONFIG ""
# Memory management
maxmemory 256mb
maxmemory-policy allkeys-lru
maxmemory-samples 5
# Persistence
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
# Append only file
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
EOF
# Set Redis config permissions
chown redis:redis "$REDIS_CONFIG"
chmod 640 "$REDIS_CONFIG"
# Start Redis service
echo -e "${BLUE}[8/12] Starting Redis service...${NC}"
systemctl enable "$REDIS_SERVICE"
systemctl start "$REDIS_SERVICE"
# Create application user
echo -e "${BLUE}[9/12] Creating application user...${NC}"
if ! id "$APP_USER" &>/dev/null; then
useradd -r -s /bin/false -d "$APP_DIR" "$APP_USER"
fi
# Create project structure
echo -e "${BLUE}[10/12] Creating project structure...${NC}"
mkdir -p "$APP_DIR"/{config,utils,middleware,routes}
chown -R "$APP_USER:$APP_USER" "$APP_DIR"
# Initialize Node.js project
cd "$APP_DIR"
sudo -u "$APP_USER" npm init -y
# Install Node.js packages
echo -e "${BLUE}[11/12] Installing Node.js packages...${NC}"
sudo -u "$APP_USER" npm install express jsonwebtoken bcryptjs redis express-rate-limit helmet cors express-validator morgan dotenv connect-redis express-session
# Create environment configuration
cat > "$APP_DIR/.env" << EOF
# JWT Configuration
JWT_SECRET=$JWT_SECRET
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=$JWT_REFRESH_SECRET
JWT_REFRESH_EXPIRES_IN=7d
# Redis Configuration
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=$REDIS_PASSWORD
# Session Configuration
SESSION_SECRET=$SESSION_SECRET
SESSION_MAX_AGE=900000
# Application Configuration
PORT=3000
NODE_ENV=production
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/.env"
chmod 600 "$APP_DIR/.env"
# Create Redis connection module
cat > "$APP_DIR/config/redis.js" << 'EOF'
const redis = require('redis');
const { promisify } = require('util');
const client = redis.createClient({
host: process.env.REDIS_HOST || '127.0.0.1',
port: process.env.REDIS_PORT || 6379,
password: process.env.REDIS_PASSWORD,
retry_strategy: (times) => {
const delay = Math.min(times * 50, 2000);
return delay;
}
});
client.on('error', (err) => {
console.error('Redis Client Error:', err);
});
client.on('connect', () => {
console.log('Connected to Redis');
});
const getAsync = promisify(client.get).bind(client);
const setAsync = promisify(client.set).bind(client);
const delAsync = promisify(client.del).bind(client);
const existsAsync = promisify(client.exists).bind(client);
module.exports = {
client,
getAsync,
setAsync,
delAsync,
existsAsync
};
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/config/redis.js"
chmod 644 "$APP_DIR/config/redis.js"
# Verification
echo -e "${BLUE}[12/12] Verifying installation...${NC}"
# Check Node.js
if ! command -v node &> /dev/null; then
echo -e "${RED}✗ Node.js installation failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Node.js $(node --version) installed${NC}"
# Check Redis
if ! systemctl is-active --quiet "$REDIS_SERVICE"; then
echo -e "${RED}✗ Redis service is not running${NC}"
exit 1
fi
echo -e "${GREEN}✓ Redis service is running${NC}"
# Check Redis authentication
if ! redis-cli -a "$REDIS_PASSWORD" ping &>/dev/null; then
echo -e "${RED}✗ Redis authentication test failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Redis authentication working${NC}"
# Check project structure
if [ ! -f "$APP_DIR/package.json" ]; then
echo -e "${RED}✗ Node.js project initialization failed${NC}"
exit 1
fi
echo -e "${GREEN}✓ Node.js project structure created${NC}"
echo -e "\n${GREEN}Installation completed successfully!${NC}"
echo -e "\n${YELLOW}Important Information:${NC}"
echo -e "Application directory: ${APP_DIR}"
echo -e "Application user: ${APP_USER}"
echo -e "Environment file: ${APP_DIR}/.env"
echo -e "Redis config: ${REDIS_CONFIG}"
echo -e "\n${YELLOW}Credentials saved in: ${APP_DIR}/.env${NC}"
echo -e "\n${GREEN}Next steps:${NC}"
echo -e "1. Create your Express.js application in ${APP_DIR}"
echo -e "2. Implement authentication routes using the JWT utilities"
echo -e "3. Configure your firewall to allow port 3000 if needed"
Review the script before running. Execute with: bash install.sh