CLAUDE: Add developer utilities and access control documentation
Added helper scripts and documentation for improved developer experience: 1. ACCESS_CONTROL.md - Comprehensive Discord whitelist documentation - Configuration examples and security best practices - Troubleshooting guide for common access issues - Details both OAuth and test token protection points 2. start-services.sh - One-command startup for backend + frontend - Logs to logs/ directory with PIDs tracked - Displays URLs and helpful information - 3-second backend initialization delay 3. stop-services.sh - Clean shutdown with process tree killing - Removes orphaned processes by pattern matching - Graceful TERM followed by KILL if needed - Cleans up PID files These utilities streamline local development by: - Reducing manual startup steps - Ensuring clean shutdown (no orphaned processes) - Providing clear access control guidance Scripts are now executable and ready to use: ./start-services.sh ./stop-services.sh 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
df2bc79aaa
commit
6e3aad9fdf
215
ACCESS_CONTROL.md
Normal file
215
ACCESS_CONTROL.md
Normal file
@ -0,0 +1,215 @@
|
||||
# Discord User Access Control
|
||||
|
||||
## Overview
|
||||
|
||||
The backend now includes Discord ID whitelist functionality to control who can access the system. This is useful for limiting access during testing/beta phases or for private leagues.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Quick Start
|
||||
|
||||
Add this line to your `backend/.env` file:
|
||||
|
||||
```bash
|
||||
# Allow specific Discord users (recommended)
|
||||
ALLOWED_DISCORD_IDS=123456789012345678,987654321098765432
|
||||
|
||||
# OR allow everyone (not recommended for production)
|
||||
ALLOWED_DISCORD_IDS=*
|
||||
|
||||
# OR leave empty to allow everyone (default, not recommended)
|
||||
ALLOWED_DISCORD_IDS=
|
||||
```
|
||||
|
||||
### Finding Discord User IDs
|
||||
|
||||
**Method 1: Enable Developer Mode in Discord**
|
||||
1. Open Discord Settings → Advanced
|
||||
2. Enable "Developer Mode"
|
||||
3. Right-click on a user → "Copy User ID"
|
||||
|
||||
**Method 2: From OAuth Response**
|
||||
- Check backend logs after a user authenticates
|
||||
- Look for: `Discord ID {id} verified in whitelist`
|
||||
|
||||
## How It Works
|
||||
|
||||
### Protection Points
|
||||
|
||||
The whitelist is checked at **two** authentication points:
|
||||
|
||||
1. **Discord OAuth Flow** (`/api/auth/discord/callback`)
|
||||
- After Discord authenticates the user
|
||||
- Before creating JWT token
|
||||
- Returns HTTP 403 if user not in whitelist
|
||||
|
||||
2. **Test Token Endpoint** (`/api/auth/token`)
|
||||
- Development/testing endpoint
|
||||
- Also checks whitelist
|
||||
- Returns HTTP 403 if Discord ID not allowed
|
||||
|
||||
### Error Response
|
||||
|
||||
When access is denied, users see:
|
||||
```json
|
||||
{
|
||||
"detail": "Access denied. Your Discord account is not authorized to access this system."
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Allow Only You and One Tester
|
||||
|
||||
```bash
|
||||
# In backend/.env
|
||||
ALLOWED_DISCORD_IDS=123456789012345678,987654321098765432
|
||||
```
|
||||
|
||||
### Allow Everyone (Development)
|
||||
|
||||
```bash
|
||||
# Option 1: Use wildcard
|
||||
ALLOWED_DISCORD_IDS=*
|
||||
|
||||
# Option 2: Leave empty
|
||||
ALLOWED_DISCORD_IDS=
|
||||
```
|
||||
|
||||
### Production Recommendation
|
||||
|
||||
```bash
|
||||
# Explicitly list all authorized users
|
||||
ALLOWED_DISCORD_IDS=user1_id,user2_id,user3_id
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Test With Authorized User
|
||||
|
||||
```bash
|
||||
# 1. Add your Discord ID to .env
|
||||
ALLOWED_DISCORD_IDS=your_discord_id
|
||||
|
||||
# 2. Restart backend
|
||||
./stop-services.sh && ./start-services.sh
|
||||
|
||||
# 3. Try to authenticate - should succeed
|
||||
```
|
||||
|
||||
### Test With Unauthorized User
|
||||
|
||||
```bash
|
||||
# 1. Set whitelist to specific IDs (not yours)
|
||||
ALLOWED_DISCORD_IDS=123456789012345678
|
||||
|
||||
# 2. Restart backend
|
||||
./stop-services.sh && ./start-services.sh
|
||||
|
||||
# 3. Try to authenticate - should get 403 error
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Backend Logs
|
||||
|
||||
Whitelist checks are logged:
|
||||
|
||||
**Allowed:**
|
||||
```
|
||||
INFO - Discord ID 123456789012345678 verified in whitelist
|
||||
INFO - User TestPlayer authenticated successfully
|
||||
```
|
||||
|
||||
**Denied:**
|
||||
```
|
||||
WARNING - Discord ID 999999999999999999 not in whitelist - access denied
|
||||
```
|
||||
|
||||
**Whitelist Disabled:**
|
||||
```
|
||||
WARNING - Discord whitelist disabled - allowing all users
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. ✅ **DO** use explicit user IDs in production
|
||||
2. ✅ **DO** keep the whitelist in `.env` (gitignored)
|
||||
3. ✅ **DO** restart backend after changing whitelist
|
||||
4. ❌ **DON'T** use `*` or empty whitelist in production
|
||||
5. ❌ **DON'T** commit Discord IDs to git
|
||||
6. ❌ **DON'T** share your `.env` file
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Access denied" for authorized user
|
||||
|
||||
**Check:**
|
||||
1. Discord ID is correct (no typos)
|
||||
2. No extra spaces in `.env`
|
||||
3. Backend has been restarted
|
||||
4. Check backend logs for whitelist warnings
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Verify your Discord ID
|
||||
# Right-click your name in Discord → Copy User ID
|
||||
|
||||
# Update .env with correct ID
|
||||
ALLOWED_DISCORD_IDS=your_correct_discord_id
|
||||
|
||||
# Restart
|
||||
./stop-services.sh && ./start-services.sh
|
||||
```
|
||||
|
||||
### Everyone getting access when they shouldn't
|
||||
|
||||
**Check:**
|
||||
1. `ALLOWED_DISCORD_IDS` is not `*`
|
||||
2. `ALLOWED_DISCORD_IDS` is not empty
|
||||
3. Backend logs show "verified in whitelist"
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Set explicit whitelist
|
||||
ALLOWED_DISCORD_IDS=your_id,friend_id
|
||||
|
||||
# Restart
|
||||
./stop-services.sh && ./start-services.sh
|
||||
```
|
||||
|
||||
### Test tokens not working
|
||||
|
||||
**Remember:** Test token endpoint (`/api/auth/token`) also respects the whitelist!
|
||||
|
||||
```bash
|
||||
# Your test token request must use an allowed Discord ID
|
||||
{
|
||||
"user_id": "test-user-1",
|
||||
"username": "TestPlayer",
|
||||
"discord_id": "your_whitelisted_discord_id" # Must be in whitelist!
|
||||
}
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Code Locations
|
||||
|
||||
- **Config**: `backend/app/config.py` - Defines `allowed_discord_ids` setting
|
||||
- **Auth Routes**: `backend/app/api/routes/auth.py` - Implements `is_discord_id_allowed()` check
|
||||
- **Discord OAuth**: Line 198-203 - Checks whitelist after Discord auth
|
||||
- **Test Tokens**: Line 376-380 - Checks whitelist for test tokens
|
||||
|
||||
### Whitelist Format
|
||||
|
||||
- **Comma-separated**: `id1,id2,id3`
|
||||
- **Spaces ignored**: `id1, id2, id3` works too
|
||||
- **Empty/missing**: Allows all users
|
||||
- **Wildcard**: `*` allows all users
|
||||
|
||||
---
|
||||
|
||||
**Created**: 2025-01-25
|
||||
**Author**: Jarvis
|
||||
**Purpose**: Control testing access via Discord user whitelist
|
||||
|
||||
48
start-services.sh
Executable file
48
start-services.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/bash
|
||||
# Start both backend and frontend services for SBA gameplay testing
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOG_DIR="$SCRIPT_DIR/logs"
|
||||
|
||||
# Create logs directory if it doesn't exist
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
echo "🚀 Starting SBA Gameplay Services..."
|
||||
echo ""
|
||||
|
||||
# Start Backend
|
||||
echo "📡 Starting Backend (FastAPI + Socket.io)..."
|
||||
cd "$SCRIPT_DIR/backend"
|
||||
uv run python -m app.main > "$LOG_DIR/backend.log" 2>&1 &
|
||||
BACKEND_PID=$!
|
||||
echo " Backend started with PID: $BACKEND_PID"
|
||||
echo " Logs: $LOG_DIR/backend.log"
|
||||
echo " API: http://localhost:8000"
|
||||
echo ""
|
||||
|
||||
# Wait for backend to initialize
|
||||
sleep 3
|
||||
|
||||
# Start Frontend
|
||||
echo "🎨 Starting Frontend (Nuxt 3)..."
|
||||
cd "$SCRIPT_DIR/frontend-sba"
|
||||
npm run dev > "$LOG_DIR/frontend.log" 2>&1 &
|
||||
FRONTEND_PID=$!
|
||||
echo " Frontend started with PID: $FRONTEND_PID"
|
||||
echo " Logs: $LOG_DIR/frontend.log"
|
||||
echo " URL: http://localhost:3000"
|
||||
echo ""
|
||||
|
||||
# Save PIDs for stop script
|
||||
echo "$BACKEND_PID" > "$LOG_DIR/backend.pid"
|
||||
echo "$FRONTEND_PID" > "$LOG_DIR/frontend.pid"
|
||||
|
||||
echo "✅ Services started successfully!"
|
||||
echo ""
|
||||
echo "📊 To view logs:"
|
||||
echo " Backend: tail -f $LOG_DIR/backend.log"
|
||||
echo " Frontend: tail -f $LOG_DIR/frontend.log"
|
||||
echo ""
|
||||
echo "🛑 To stop services: ./stop-services.sh"
|
||||
99
stop-services.sh
Executable file
99
stop-services.sh
Executable file
@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
# Stop both backend and frontend services
|
||||
# Enhanced to kill entire process trees and clean up orphans
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOG_DIR="$SCRIPT_DIR/logs"
|
||||
|
||||
echo "🛑 Stopping SBA Gameplay Services..."
|
||||
echo ""
|
||||
|
||||
# Function to kill process tree
|
||||
kill_tree() {
|
||||
local pid=$1
|
||||
local sig=${2:-TERM}
|
||||
|
||||
# Get all child PIDs
|
||||
local children=$(pgrep -P "$pid" 2>/dev/null || true)
|
||||
|
||||
# Kill children first
|
||||
for child in $children; do
|
||||
kill_tree "$child" "$sig"
|
||||
done
|
||||
|
||||
# Kill the parent
|
||||
if ps -p "$pid" > /dev/null 2>&1; then
|
||||
kill -"$sig" "$pid" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop Backend
|
||||
if [ -f "$LOG_DIR/backend.pid" ]; then
|
||||
BACKEND_PID=$(cat "$LOG_DIR/backend.pid")
|
||||
if ps -p "$BACKEND_PID" > /dev/null 2>&1; then
|
||||
echo "📡 Stopping Backend (PID: $BACKEND_PID)..."
|
||||
kill_tree "$BACKEND_PID" TERM
|
||||
sleep 1
|
||||
# Force kill if still running
|
||||
if ps -p "$BACKEND_PID" > /dev/null 2>&1; then
|
||||
kill_tree "$BACKEND_PID" KILL
|
||||
fi
|
||||
echo " ✓ Backend stopped"
|
||||
else
|
||||
echo " ⚠ Backend process not found"
|
||||
fi
|
||||
rm -f "$LOG_DIR/backend.pid"
|
||||
else
|
||||
echo " ⚠ No backend PID file found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Stop Frontend
|
||||
if [ -f "$LOG_DIR/frontend.pid" ]; then
|
||||
FRONTEND_PID=$(cat "$LOG_DIR/frontend.pid")
|
||||
if ps -p "$FRONTEND_PID" > /dev/null 2>&1; then
|
||||
echo "🎨 Stopping Frontend (PID: $FRONTEND_PID)..."
|
||||
kill_tree "$FRONTEND_PID" TERM
|
||||
sleep 1
|
||||
# Force kill if still running
|
||||
if ps -p "$FRONTEND_PID" > /dev/null 2>&1; then
|
||||
kill_tree "$FRONTEND_PID" KILL
|
||||
fi
|
||||
echo " ✓ Frontend stopped"
|
||||
else
|
||||
echo " ⚠ Frontend process not found"
|
||||
fi
|
||||
rm -f "$LOG_DIR/frontend.pid"
|
||||
else
|
||||
echo " ⚠ No frontend PID file found"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Aggressive cleanup: kill ALL related processes by pattern matching
|
||||
echo "🔍 Checking for any remaining processes..."
|
||||
|
||||
# Kill all uvicorn processes for this app
|
||||
BACKEND_PIDS=$(pgrep -f "uvicorn.*app\.main" 2>/dev/null || true)
|
||||
if [ -n "$BACKEND_PIDS" ]; then
|
||||
echo " Found orphaned backend processes: $BACKEND_PIDS"
|
||||
for pid in $BACKEND_PIDS; do
|
||||
kill_tree "$pid" KILL
|
||||
done
|
||||
echo " ✓ Killed orphaned backend processes"
|
||||
fi
|
||||
|
||||
# Kill all nuxt dev processes in this directory
|
||||
FRONTEND_PIDS=$(pgrep -f "nuxt.*dev" | while read pid; do
|
||||
if ps -p $pid -o args= | grep -q "$SCRIPT_DIR/frontend-sba"; then
|
||||
echo $pid
|
||||
fi
|
||||
done)
|
||||
if [ -n "$FRONTEND_PIDS" ]; then
|
||||
echo " Found orphaned frontend processes: $FRONTEND_PIDS"
|
||||
for pid in $FRONTEND_PIDS; do
|
||||
kill_tree "$pid" KILL
|
||||
done
|
||||
echo " ✓ Killed orphaned frontend processes"
|
||||
fi
|
||||
|
||||
echo "✅ Services stopped successfully!"
|
||||
Loading…
Reference in New Issue
Block a user