add toggle for allowing registrations from the frontend

This commit is contained in:
2025-08-10 13:36:07 +01:00
parent b790b3bd76
commit a53c50b8b4
4 changed files with 294 additions and 3 deletions

View File

@@ -9,6 +9,10 @@ MONGODB_DATABASE=scoffer
# JWT Secret for Backend (CHANGE THIS IN PRODUCTION!)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
# Registration Control
# Set to 'false' to disable user registration (recommended for production)
ALLOW_REGISTRATION=false
# Port Configuration (customize as needed for your server)
FRONTEND_PORT=3000
BACKEND_PORT=5000
@@ -21,8 +25,5 @@ MONGO_EXPRESS_PORT=8081
# Replace 'your-domain.com' with your actual domain
REACT_APP_API_URL=https://your-domain.com/api
# Alternative: If backend runs on different port/subdomain
# REACT_APP_API_URL=https://api.your-domain.com
# For local testing with containers (no SSL)
# REACT_APP_API_URL=http://localhost:5000/api

281
REGISTRATION_CONTROL.md Normal file
View File

@@ -0,0 +1,281 @@
# Registration Control Guide
## Overview
The application now supports controlling user registration through an environment variable. This is a critical security feature that allows administrators to disable new user registrations in production environments while keeping existing user login functionality intact.
## Environment Variable
| Variable | Default | Description |
|----------|---------|-------------|
| `ALLOW_REGISTRATION` | `true` | Controls whether new user registration is allowed |
## Configuration
### Enable Registration (Default)
```bash
ALLOW_REGISTRATION=true
```
or simply omit the variable (defaults to `true`)
### Disable Registration
```bash
ALLOW_REGISTRATION=false
```
## Usage Scenarios
### Development Environment
**Recommended**: Enable registration for testing
```bash
# .env or .env.local
ALLOW_REGISTRATION=true
```
### Production Environment
**Recommended**: Disable registration after initial setup
```bash
# .env.production
ALLOW_REGISTRATION=false
```
### Staging Environment
**Optional**: Enable for testing, disable for demos
```bash
# .env.staging
ALLOW_REGISTRATION=true # or false depending on needs
```
## Implementation Details
### Backend Behavior
**When `ALLOW_REGISTRATION=true` (default)**:
- `POST /api/users/register` accepts new registrations
- Returns 201 with user data and JWT token on success
- Returns 400 if user already exists
**When `ALLOW_REGISTRATION=false`**:
- `POST /api/users/register` returns 403 Forbidden
- Response: `{"error": "Registration is currently disabled"}`
- Login functionality remains unaffected
### Frontend Considerations
The frontend should handle the 403 response gracefully:
```javascript
// Example error handling in registration form
try {
const response = await api.post('/users/register', userData);
// Handle success
} catch (error) {
if (error.response?.status === 403) {
// Registration disabled
setError('Registration is currently disabled. Please contact an administrator.');
} else {
// Other errors (validation, user exists, etc.)
setError(error.response?.data?.error || 'Registration failed');
}
}
```
## Deployment Examples
### Quick Setup Commands
**Enable registration**:
```bash
echo "ALLOW_REGISTRATION=true" >> .env
docker-compose up -d --build
```
**Disable registration**:
```bash
echo "ALLOW_REGISTRATION=false" >> .env
docker-compose up -d --build
```
**Toggle without rebuild** (if container is already running):
```bash
# Update .env file
sed -i 's/ALLOW_REGISTRATION=.*/ALLOW_REGISTRATION=false/' .env
# Restart backend container to pick up new env var
docker-compose restart backend
```
### Environment-Specific Deployments
**Development with registration enabled**:
```bash
# .env.dev
ALLOW_REGISTRATION=true
REACT_APP_API_URL=http://localhost:5000/api
JWT_SECRET=dev-secret-key
# Deploy
cp .env.dev .env
docker-compose up -d
```
**Production with registration disabled**:
```bash
# .env.prod
ALLOW_REGISTRATION=false
REACT_APP_API_URL=https://your-domain.com/api
JWT_SECRET=super-secure-production-key
# Deploy
cp .env.prod .env
docker-compose up -d --build
```
## Security Best Practices
### 1. Disable Registration in Production
```bash
# Always set this in production
ALLOW_REGISTRATION=false
```
### 2. Create Initial Admin User
Before disabling registration, ensure you have at least one admin user:
```bash
# Method 1: Enable registration temporarily
ALLOW_REGISTRATION=true docker-compose up -d
# Register your admin user via frontend/API
# Then disable registration
ALLOW_REGISTRATION=false docker-compose restart backend
# Method 2: Create user directly in database (advanced)
docker-compose exec mongodb mongosh scoffer
# Use MongoDB commands to create user
```
### 3. Monitor Registration Attempts
Consider adding logging for blocked registration attempts:
```javascript
// In backend/routes/users.js (optional enhancement)
if (!registrationEnabled) {
console.log(`Registration attempt blocked from IP: ${req.ip}`);
return res.status(403).json({
error: 'Registration is currently disabled'
});
}
```
## Troubleshooting
### Registration Still Working After Disabling
**Cause**: Environment variable not picked up by container
**Solutions**:
1. Restart the backend container:
```bash
docker-compose restart backend
```
2. Rebuild if env var was added after initial build:
```bash
docker-compose up -d --build backend
```
3. Verify environment variable in container:
```bash
docker-compose exec backend env | grep ALLOW_REGISTRATION
```
### Frontend Shows Registration Form When Disabled
**Cause**: Frontend doesn't know registration is disabled until API call
**Solutions**:
1. Add API endpoint to check registration status:
```javascript
// GET /api/users/registration-status
router.get('/registration-status', (req, res) => {
res.json({
enabled: process.env.ALLOW_REGISTRATION !== 'false'
});
});
```
2. Hide registration form based on API response
3. Handle 403 error gracefully in registration form
### Users Can't Login After Disabling Registration
**Issue**: This should NOT happen - login is separate from registration
**Check**:
1. Verify `ALLOW_REGISTRATION` only affects `/register` endpoint
2. Ensure `/login` endpoint is unaffected
3. Check JWT_SECRET hasn't changed
## API Reference
### Registration Endpoint
**Endpoint**: `POST /api/users/register`
**When Enabled** (`ALLOW_REGISTRATION=true`):
```bash
curl -X POST http://localhost:5000/api/users/register \
-H "Content-Type: application/json" \
-d '{"username":"test","email":"test@example.com","password":"password123"}'
# Response: 201 Created
{
"message": "User created successfully",
"token": "jwt-token-here",
"user": {
"id": "user-id",
"username": "test",
"email": "test@example.com"
}
}
```
**When Disabled** (`ALLOW_REGISTRATION=false`):
```bash
curl -X POST http://localhost:5000/api/users/register \
-H "Content-Type: application/json" \
-d '{"username":"test","email":"test@example.com","password":"password123"}'
# Response: 403 Forbidden
{
"error": "Registration is currently disabled"
}
```
### Login Endpoint (Unaffected)
**Endpoint**: `POST /api/users/login`
```bash
curl -X POST http://localhost:5000/api/users/login \
-H "Content-Type: application/json" \
-d '{"email":"existing@example.com","password":"password123"}'
# Response: 200 OK (regardless of ALLOW_REGISTRATION setting)
{
"message": "Login successful",
"token": "jwt-token-here",
"user": {
"id": "user-id",
"username": "existing",
"email": "existing@example.com"
}
}
```
## Quick Reference
| Action | Command |
|--------|---------|
| Enable registration | `ALLOW_REGISTRATION=true` |
| Disable registration | `ALLOW_REGISTRATION=false` |
| Check current setting | `docker-compose exec backend env \| grep ALLOW_REGISTRATION` |
| Restart backend | `docker-compose restart backend` |
| Test registration | `curl -X POST localhost:5000/api/users/register -H "Content-Type: application/json" -d '{"username":"test","email":"test@test.com","password":"test123"}'` |

View File

@@ -6,6 +6,14 @@ const User = require('../models/User');
// Register new user
router.post('/register', async (req, res) => {
try {
// Check if registration is enabled
const registrationEnabled = process.env.ALLOW_REGISTRATION !== 'false';
if (!registrationEnabled) {
return res.status(403).json({
error: 'Registration is currently disabled'
});
}
const { username, email, password } = req.body;
// Check if user already exists

View File

@@ -33,6 +33,7 @@ services:
- MONGODB_PORT=27017
- MONGODB_DATABASE=scoffer
- JWT_SECRET=${JWT_SECRET}
- ALLOW_REGISTRATION=${ALLOW_REGISTRATION:-true}
ports:
- "${BACKEND_PORT:-5000}:5000"
depends_on: