Skip to main content

Overview

The DEMET Backend API uses environment variables for configuration management through the dotenv package. This approach keeps sensitive data out of your codebase and allows different configurations for development, staging, and production environments.

Environment Variables

All configuration is stored in a .env file at the root of your project.

Required Variables

DATABASE_URL
string
required
PostgreSQL connection stringFormat: postgresql://username:password@host:port/databaseExample: postgresql://postgres:mypassword@localhost:5432/demet_db
ACCESS_SECRET
string
required
Secret key for signing access tokens (JWT)Recommendation: Generate a strong random string (32+ characters)Example: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
ACCESS_EXPIRE_IN
string
required
Expiration time for access tokensFormat: Uses jsonwebtoken time spans (e.g., 60, 2d, 10h, 7d)Default: 1h (1 hour)Recommendation: Short duration (15m - 1h) for better security
REFRESH_SECRET
string
required
Secret key for signing refresh tokens (JWT)Important: Must be different from ACCESS_SECRETExample: z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4
REFRESH_EXPIRE_IN
string
required
Expiration time for refresh tokensDefault: 7d (7 days)Recommendation: Longer duration (7d - 30d) for better UX
PORT
number
required
Port number where the server will listenDefault: 3002Range: 1024-65535 (avoid reserved ports)
GOOGLE_USER
string
required
Gmail address for sending emails via NodemailerExample: [email protected] or [email protected]
GOOGLE_PWD
string
required
Gmail App Password (not your regular password)Setup: Generate at Google App PasswordsFormat: 16-character string without spaces
EMAIL_ADMIN
string
required
Administrator email address for receiving notificationsExample: [email protected]Purpose: Receives alerts about new reservation requests

Complete Configuration Example

DATABASE_URL=postgresql://postgres:devpassword@localhost:5432/demet_dev
ACCESS_SECRET=dev-access-secret-key-change-in-production
ACCESS_EXPIRE_IN=1h
REFRESH_SECRET=dev-refresh-secret-key-change-in-production
REFRESH_EXPIRE_IN=7d
PORT=3002
[email protected]
GOOGLE_PWD=abcd efgh ijkl mnop
[email protected]

Configuration by Environment

Development Environment

1

Local Database

Use a local PostgreSQL instance:
DATABASE_URL=postgresql://postgres:password@localhost:5432/demet_dev
2

Relaxed Token Expiration

Longer access token duration for easier debugging:
ACCESS_EXPIRE_IN=8h
REFRESH_EXPIRE_IN=30d
3

Test Email Account

Use a dedicated test Gmail account:
[email protected]
EMAIL_ADMIN=dev@localhost

Production Environment

1

Secure Database Connection

Use SSL and strong credentials:
DATABASE_URL=postgresql://user:password@host:5432/db?sslmode=require
2

Strong JWT Secrets

Generate cryptographically secure secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
3

Short Access Token Duration

Minimize security risk:
ACCESS_EXPIRE_IN=15m
4

Production Email

Use your domain’s email:

Loading Configuration

The application loads environment variables at startup:
import dotenv from 'dotenv';

// Load environment variables from .env file
dotenv.config();

const PORT = process.env.PORT || 3000;

app.listen(PORT, "0.0.0.0", () => {
  console.log(`Servidor escuchando en http://localhost:${PORT}`);
});

Security Best Practices

Never commit sensitive credentials to version control!

1. Add .env to .gitignore

.gitignore
# Environment variables
.env
.env.local
.env.*.local

# Dependencies
node_modules/

# Logs
*.log

2. Use Different Secrets Per Environment

# Development
ACCESS_SECRET=dev-secret-abc123xyz

# Production  
ACCESS_SECRET=prod-secret-xyz789def
Different secrets prevent token reuse across environments.

3. Rotate Secrets Regularly

Change JWT secrets periodically:
  • Development: Monthly
  • Production: Quarterly or after suspected breach

4. Use Strong Passwords

Generate secure random strings:
# Generate 32-byte hex string
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Generate base64 string
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

# Or use OpenSSL
openssl rand -hex 32

5. Database Connection Security

# Use SSL, read-only replicas, connection pooling
DATABASE_URL=postgresql://user:pass@host:5432/db?sslmode=require&poolsize=10

Gmail Configuration

Setting Up App Passwords

1

Enable 2-Factor Authentication

Go to Google Account Security and enable 2FA
2

Generate App Password

Visit App Passwords
  • Select app: “Mail”
  • Select device: “Other (Custom name)”
  • Enter: “DEMET Backend”
  • Click “Generate”
3

Copy Password

Copy the 16-character password (spaces don’t matter):
GOOGLE_PWD=abcdefghijklmnop
Regular Gmail passwords won’t work. You must use an App Password.

JWT Token Configuration

Token Structure

The API uses dual-token authentication:
  1. Access Token - Short-lived, stored in HTTP-only cookie
  2. Refresh Token - Long-lived, used to get new access tokens

Token Expiration Strategy

Access Token

Duration: 15m - 1hWhy short? Minimizes damage if compromisedStored: HTTP-only cookie

Refresh Token

Duration: 7d - 30dWhy long? Better user experienceStored: HTTP-only cookie

Example Configuration

# Recommended for production
ACCESS_EXPIRE_IN=15m
REFRESH_EXPIRE_IN=7d

# Alternative for development
ACCESS_EXPIRE_IN=8h
REFRESH_EXPIRE_IN=30d

CORS Configuration

CORS is configured in server.js:
app.use(cors({
  origin: [
    "https://clubmetabros.vercel.app",  // Production frontend
    "http://localhost:3000"              // Local development
  ],
  credentials: true  // Allow cookies
}));
To add more origins:
const allowedOrigins = [
  process.env.FRONTEND_URL_PROD,
  process.env.FRONTEND_URL_DEV,
  "http://localhost:3000",
  "http://localhost:3001"
];

app.use(cors({
  origin: allowedOrigins,
  credentials: true
}));

Validation

Verify your configuration:
import dotenv from 'dotenv';
dotenv.config();

const requiredVars = [
  'DATABASE_URL',
  'ACCESS_SECRET',
  'REFRESH_SECRET',
  'PORT',
  'GOOGLE_USER',
  'GOOGLE_PWD',
  'EMAIL_ADMIN'
];

const missing = requiredVars.filter(v => !process.env[v]);

if (missing.length > 0) {
  console.error('Missing required environment variables:');
  console.error(missing.join(', '));
  process.exit(1);
}

console.log('✓ All required environment variables are set');

Troubleshooting

  • Ensure .env is in the project root
  • Check file name (no spaces, no extensions)
  • Verify dotenv.config() is called before using variables
  • Try absolute path: dotenv.config({ path: '/path/to/.env' })
  • Verify PostgreSQL is running
  • Test connection string format
  • Check network access and firewall rules
  • Validate username/password
  • Use App Password, not regular password
  • Enable 2FA on Gmail account
  • Check for spaces in GOOGLE_PWD
  • Verify “Less secure app access” is OFF (use App Passwords instead)
  • Ensure ACCESS_SECRET and REFRESH_SECRET are different
  • Check for leading/trailing whitespace
  • Verify secrets match on all servers
  • Don’t change secrets without invalidating existing tokens

Next Steps

Database Setup

Configure PostgreSQL schema and connections

Email Notifications

Set up email templates and sending

Authentication

Learn about JWT authentication endpoints

Deployment

Deploy to production environments

Build docs developers (and LLMs) love