Spaces:
Sleeping
Sleeping
test
Browse files- .env.example +141 -0
- check_token_config.sh +54 -0
- test_token_expiry.py +106 -0
.env.example
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# =============================================================================
|
| 2 |
+
# API Gateway Environment Configuration
|
| 3 |
+
# =============================================================================
|
| 4 |
+
# Copy this file to .env and fill in your actual values
|
| 5 |
+
# Never commit the .env file to version control!
|
| 6 |
+
|
| 7 |
+
# -----------------------------------------------------------------------------
|
| 8 |
+
# Environment
|
| 9 |
+
# -----------------------------------------------------------------------------
|
| 10 |
+
# Options: "production" or "development"
|
| 11 |
+
# Affects cookie security settings and database naming
|
| 12 |
+
ENVIRONMENT=development
|
| 13 |
+
|
| 14 |
+
# -----------------------------------------------------------------------------
|
| 15 |
+
# Database
|
| 16 |
+
# -----------------------------------------------------------------------------
|
| 17 |
+
# Database name (filename will be {DB_NAME}_{ENVIRONMENT}.db)
|
| 18 |
+
DB_NAME=apigateway
|
| 19 |
+
|
| 20 |
+
# Reset database on startup (CAUTION: deletes all data)
|
| 21 |
+
# RESET_DB=true
|
| 22 |
+
|
| 23 |
+
# -----------------------------------------------------------------------------
|
| 24 |
+
# CORS Configuration
|
| 25 |
+
# -----------------------------------------------------------------------------
|
| 26 |
+
# Comma-separated list of allowed origins for CORS (NO SPACES!)
|
| 27 |
+
# IMPORTANT: Required for cookies to work with credentials
|
| 28 |
+
# Production example: CORS_ORIGINS=https://app.yourdomain.com,https://www.yourdomain.com
|
| 29 |
+
# Development example: CORS_ORIGINS=http://localhost:3000,http://localhost:5173
|
| 30 |
+
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
|
| 31 |
+
|
| 32 |
+
# -----------------------------------------------------------------------------
|
| 33 |
+
# JWT Authentication
|
| 34 |
+
# -----------------------------------------------------------------------------
|
| 35 |
+
# Secret key for signing JWT tokens (REQUIRED)
|
| 36 |
+
# Generate with: python -c "import secrets; print(secrets.token_urlsafe(64))"
|
| 37 |
+
JWT_SECRET=your-secret-key-here-change-me
|
| 38 |
+
|
| 39 |
+
# JWT algorithm for token signing
|
| 40 |
+
JWT_ALGORITHM=HS256
|
| 41 |
+
|
| 42 |
+
# Access token expiry in minutes (short-lived, for API requests)
|
| 43 |
+
# Production: 5-15 minutes | Development: 30-60 minutes
|
| 44 |
+
JWT_ACCESS_EXPIRY_MINUTES=15
|
| 45 |
+
|
| 46 |
+
# Refresh token expiry in days (long-lived, for getting new access tokens)
|
| 47 |
+
# Production: 7-14 days | Development: 30-90 days
|
| 48 |
+
JWT_REFRESH_EXPIRY_DAYS=7
|
| 49 |
+
|
| 50 |
+
# -----------------------------------------------------------------------------
|
| 51 |
+
# Google OAuth
|
| 52 |
+
# -----------------------------------------------------------------------------
|
| 53 |
+
# Google OAuth Client ID for Google Sign-In
|
| 54 |
+
# Get from: https://console.cloud.google.com/apis/credentials
|
| 55 |
+
AUTH_SIGN_IN_GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
|
| 56 |
+
|
| 57 |
+
# -----------------------------------------------------------------------------
|
| 58 |
+
# Admin Configuration
|
| 59 |
+
# -----------------------------------------------------------------------------
|
| 60 |
+
# Comma-separated list of admin email addresses
|
| 61 |
+
# Example: ADMIN_EMAILS=admin@example.com,boss@example.com
|
| 62 |
+
ADMIN_EMAILS=
|
| 63 |
+
|
| 64 |
+
# -----------------------------------------------------------------------------
|
| 65 |
+
# Payment Integration (Razorpay)
|
| 66 |
+
# -----------------------------------------------------------------------------
|
| 67 |
+
# Razorpay API credentials
|
| 68 |
+
# Get from: https://dashboard.razorpay.com/app/keys
|
| 69 |
+
RAZORPAY_KEY_ID=your_razorpay_key_id
|
| 70 |
+
RAZORPAY_KEY_SECRET=your_razorpay_key_secret
|
| 71 |
+
|
| 72 |
+
# Razorpay webhook secret for verifying webhook signatures
|
| 73 |
+
# Get from: https://dashboard.razorpay.com/app/webhooks
|
| 74 |
+
RAZORPAY_WEBHOOK_SECRET=your_webhook_secret
|
| 75 |
+
|
| 76 |
+
# -----------------------------------------------------------------------------
|
| 77 |
+
# Google Drive Backup (Optional)
|
| 78 |
+
# -----------------------------------------------------------------------------
|
| 79 |
+
# Path to Google Drive service account credentials JSON file
|
| 80 |
+
# Used for automatic database backups to Google Drive
|
| 81 |
+
# GOOGLE_DRIVE_CREDENTIALS_PATH=/path/to/credentials.json
|
| 82 |
+
|
| 83 |
+
# Google Drive folder ID where backups should be stored
|
| 84 |
+
# GOOGLE_DRIVE_FOLDER_ID=your_folder_id
|
| 85 |
+
|
| 86 |
+
# -----------------------------------------------------------------------------
|
| 87 |
+
# Gemini AI API Keys
|
| 88 |
+
# -----------------------------------------------------------------------------
|
| 89 |
+
# Comma-separated list of Gemini API keys for video generation
|
| 90 |
+
# Get from: https://makersuite.google.com/app/apikey
|
| 91 |
+
# Example: GEMINI_API_KEYS=key1,key2,key3
|
| 92 |
+
GEMINI_API_KEYS=your-gemini-api-key
|
| 93 |
+
|
| 94 |
+
# Number of concurrent jobs per API key (rate limiting)
|
| 95 |
+
JOB_PER_API_KEY=2
|
| 96 |
+
|
| 97 |
+
# Enable mock mode for testing without consuming API credits
|
| 98 |
+
# GEMINI_MOCK_MODE=true
|
| 99 |
+
|
| 100 |
+
# -----------------------------------------------------------------------------
|
| 101 |
+
# Email Configuration (Optional)
|
| 102 |
+
# -----------------------------------------------------------------------------
|
| 103 |
+
# SMTP settings for sending emails (contact form, notifications, etc.)
|
| 104 |
+
# SMTP_HOST=smtp.gmail.com
|
| 105 |
+
# SMTP_PORT=587
|
| 106 |
+
# SMTP_USER=your-email@gmail.com
|
| 107 |
+
# SMTP_PASSWORD=your-app-password
|
| 108 |
+
# SMTP_FROM=noreply@yourdomain.com
|
| 109 |
+
|
| 110 |
+
# -----------------------------------------------------------------------------
|
| 111 |
+
# Logging
|
| 112 |
+
# -----------------------------------------------------------------------------
|
| 113 |
+
# Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL
|
| 114 |
+
LOG_LEVEL=INFO
|
| 115 |
+
|
| 116 |
+
# -----------------------------------------------------------------------------
|
| 117 |
+
# Server Configuration
|
| 118 |
+
# -----------------------------------------------------------------------------
|
| 119 |
+
# Server host and port (for uvicorn)
|
| 120 |
+
# HOST=0.0.0.0
|
| 121 |
+
# PORT=8000
|
| 122 |
+
|
| 123 |
+
# Number of worker processes
|
| 124 |
+
# WORKERS=4
|
| 125 |
+
|
| 126 |
+
# -----------------------------------------------------------------------------
|
| 127 |
+
# Feature Flags (Optional)
|
| 128 |
+
# -----------------------------------------------------------------------------
|
| 129 |
+
# Enable/disable specific features
|
| 130 |
+
# ENABLE_RATE_LIMITING=true
|
| 131 |
+
# ENABLE_AUDIT_LOGGING=true
|
| 132 |
+
# ENABLE_AUTO_BACKUP=true
|
| 133 |
+
|
| 134 |
+
# =============================================================================
|
| 135 |
+
# Notes
|
| 136 |
+
# =============================================================================
|
| 137 |
+
# 1. JWT_SECRET is REQUIRED - generate a secure one before deploying!
|
| 138 |
+
# 2. In production, set ENVIRONMENT=production for proper cookie security
|
| 139 |
+
# 3. CORS_ORIGINS must match your frontend domain exactly (including https://)
|
| 140 |
+
# 4. Never commit your .env file - it contains sensitive credentials
|
| 141 |
+
# 5. Keep your .env.example file updated as you add new variables
|
check_token_config.sh
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
# Quick Token Configuration Diagnostic
|
| 3 |
+
|
| 4 |
+
echo "=========================================="
|
| 5 |
+
echo " JWT Token Configuration Diagnostic"
|
| 6 |
+
echo "=========================================="
|
| 7 |
+
|
| 8 |
+
echo -e "\n1οΈβ£ Environment Variables:"
|
| 9 |
+
echo " JWT_ACCESS_EXPIRY_MINUTES: $(grep JWT_ACCESS_EXPIRY_MINUTES .env 2>/dev/null | cut -d'=' -f2 || echo 'NOT SET')"
|
| 10 |
+
echo " JWT_REFRESH_EXPIRY_DAYS: $(grep JWT_REFRESH_EXPIRY_DAYS .env 2>/dev/null | cut -d'=' -f2 || echo 'NOT SET')"
|
| 11 |
+
|
| 12 |
+
echo -e "\n2οΈβ£ Server Status:"
|
| 13 |
+
if pgrep -f "python app.py" > /dev/null; then
|
| 14 |
+
echo " β
Server is running"
|
| 15 |
+
echo " PID: $(pgrep -f 'python app.py')"
|
| 16 |
+
echo " Started: $(ps -p $(pgrep -f 'python app.py') -o lstart= 2>/dev/null)"
|
| 17 |
+
else
|
| 18 |
+
echo " β Server is NOT running"
|
| 19 |
+
fi
|
| 20 |
+
|
| 21 |
+
echo -e "\n3οΈβ£ File Modification Times:"
|
| 22 |
+
echo " .env modified: $(stat -c '%y' .env 2>/dev/null | cut -d'.' -f1 || echo 'Unknown')"
|
| 23 |
+
|
| 24 |
+
echo -e "\n4οΈβ£ Recommendation:"
|
| 25 |
+
if pgrep -f "python app.py" > /dev/null; then
|
| 26 |
+
SERVER_START=$(ps -p $(pgrep -f "python app.py") -o etimes= | tr -d ' ')
|
| 27 |
+
if [ -f .env ]; then
|
| 28 |
+
ENV_MOD=$(stat -c '%Y' .env)
|
| 29 |
+
SERVER_START_TIME=$(($(date +%s) - SERVER_START))
|
| 30 |
+
|
| 31 |
+
if [ $ENV_MOD -gt $SERVER_START_TIME ]; then
|
| 32 |
+
echo " β οΈ .env was modified AFTER server started!"
|
| 33 |
+
echo " β οΈ Server is using OLD configuration!"
|
| 34 |
+
echo " "
|
| 35 |
+
echo " π ACTION REQUIRED: Restart the server"
|
| 36 |
+
echo " "
|
| 37 |
+
echo " Run these commands:"
|
| 38 |
+
echo " pkill -f 'python app.py'"
|
| 39 |
+
echo " python app.py"
|
| 40 |
+
else
|
| 41 |
+
echo " β
Server has latest .env configuration"
|
| 42 |
+
echo " "
|
| 43 |
+
echo " π‘ Token expiry IS working, but you may not see it because:"
|
| 44 |
+
echo " - Frontend automatically refreshes tokens"
|
| 45 |
+
echo " - Refresh happens silently every ~1 minute"
|
| 46 |
+
echo " "
|
| 47 |
+
echo " To verify, check browser DevTools β Network tab for /auth/refresh calls"
|
| 48 |
+
fi
|
| 49 |
+
fi
|
| 50 |
+
else
|
| 51 |
+
echo " π Start the server first: python app.py"
|
| 52 |
+
fi
|
| 53 |
+
|
| 54 |
+
echo -e "\n=========================================="
|
test_token_expiry.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Simple JWT Token Expiry Test - Direct approach
|
| 4 |
+
"""
|
| 5 |
+
import os
|
| 6 |
+
import jwt
|
| 7 |
+
import time
|
| 8 |
+
from datetime import datetime, timedelta
|
| 9 |
+
from dotenv import load_dotenv
|
| 10 |
+
|
| 11 |
+
# Load environment variables
|
| 12 |
+
load_dotenv()
|
| 13 |
+
|
| 14 |
+
def test_token_expiry():
|
| 15 |
+
"""Test JWT token creation and expiry"""
|
| 16 |
+
|
| 17 |
+
print("=" * 70)
|
| 18 |
+
print("JWT Token Expiry Test")
|
| 19 |
+
print("=" * 70)
|
| 20 |
+
|
| 21 |
+
# Get environment variables
|
| 22 |
+
access_expiry_minutes = int(os.getenv("JWT_ACCESS_EXPIRY_MINUTES", "15"))
|
| 23 |
+
jwt_secret = os.getenv("JWT_SECRET")
|
| 24 |
+
jwt_algorithm = os.getenv("JWT_ALGORITHM", "HS256")
|
| 25 |
+
|
| 26 |
+
print(f"\nπ Current Configuration:")
|
| 27 |
+
print(f" JWT_ACCESS_EXPIRY_MINUTES: {access_expiry_minutes} minute(s)")
|
| 28 |
+
print(f" JWT_ALGORITHM: {jwt_algorithm}")
|
| 29 |
+
print(f" JWT_SECRET: {'β
Set' if jwt_secret else 'β NOT SET'}")
|
| 30 |
+
|
| 31 |
+
if not jwt_secret:
|
| 32 |
+
print("\nβ ERROR: JWT_SECRET not set!")
|
| 33 |
+
return
|
| 34 |
+
|
| 35 |
+
# Create token manually
|
| 36 |
+
print(f"\nπ Creating test token...")
|
| 37 |
+
now = datetime.utcnow()
|
| 38 |
+
expires_at = now + timedelta(minutes=access_expiry_minutes)
|
| 39 |
+
|
| 40 |
+
payload = {
|
| 41 |
+
"sub": "test_user_123",
|
| 42 |
+
"email": "test@example.com",
|
| 43 |
+
"type": "access",
|
| 44 |
+
"tv": 1,
|
| 45 |
+
"iat": now,
|
| 46 |
+
"exp": expires_at
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
token = jwt.encode(payload, jwt_secret, algorithm=jwt_algorithm)
|
| 50 |
+
print(f" β
Token created")
|
| 51 |
+
print(f" Issued at: {now}")
|
| 52 |
+
print(f" Expires at: {expires_at}")
|
| 53 |
+
print(f" Token lifetime: {access_expiry_minutes} minute(s)")
|
| 54 |
+
|
| 55 |
+
# Verify token is valid now
|
| 56 |
+
print(f"\nβ
Verifying token immediately...")
|
| 57 |
+
try:
|
| 58 |
+
decoded = jwt.decode(token, jwt_secret, algorithms=[jwt_algorithm])
|
| 59 |
+
print(f" β
Token is valid")
|
| 60 |
+
print(f" User: {decoded['sub']}")
|
| 61 |
+
print(f" Email: {decoded['email']}")
|
| 62 |
+
except jwt.ExpiredSignatureError:
|
| 63 |
+
print(f" β Token already expired (shouldn't happen!)")
|
| 64 |
+
return
|
| 65 |
+
except Exception as e:
|
| 66 |
+
print(f" β Error: {e}")
|
| 67 |
+
return
|
| 68 |
+
|
| 69 |
+
# If very short expiry, wait and test
|
| 70 |
+
if access_expiry_minutes <= 5:
|
| 71 |
+
wait_seconds = (access_expiry_minutes * 60) + 5
|
| 72 |
+
print(f"\nβ³ Waiting {wait_seconds} seconds for token to expire...")
|
| 73 |
+
print(f" Token should expire at: {expires_at}")
|
| 74 |
+
|
| 75 |
+
for i in range(wait_seconds):
|
| 76 |
+
remaining = wait_seconds - i
|
| 77 |
+
if remaining % 10 == 0 or remaining <= 10:
|
| 78 |
+
print(f" β±οΈ {remaining} seconds remaining...")
|
| 79 |
+
time.sleep(1)
|
| 80 |
+
|
| 81 |
+
print(f"\nπ Testing token after {wait_seconds} seconds...")
|
| 82 |
+
print(f" Current time: {datetime.utcnow()}")
|
| 83 |
+
|
| 84 |
+
try:
|
| 85 |
+
decoded = jwt.decode(token, jwt_secret, algorithms=[jwt_algorithm])
|
| 86 |
+
print(f" β Token STILL VALID (This is a problem!)")
|
| 87 |
+
print(f" This means the token didn't expire as expected")
|
| 88 |
+
except jwt.ExpiredSignatureError:
|
| 89 |
+
print(f" β
Token EXPIRED (This is correct!)")
|
| 90 |
+
print(f" Token expiry is working properly")
|
| 91 |
+
except Exception as e:
|
| 92 |
+
print(f" β οΈ Error: {e}")
|
| 93 |
+
else:
|
| 94 |
+
print(f"\nπ‘ Token expiry is set to {access_expiry_minutes} minutes")
|
| 95 |
+
print(f" This is too long to wait in this test")
|
| 96 |
+
print(f" To test expiry quickly:")
|
| 97 |
+
print(f" 1. Set JWT_ACCESS_EXPIRY_MINUTES=1 in .env")
|
| 98 |
+
print(f" 2. Restart the server")
|
| 99 |
+
print(f" 3. Run this test again")
|
| 100 |
+
|
| 101 |
+
print("\n" + "=" * 70)
|
| 102 |
+
print("Test Complete!")
|
| 103 |
+
print("=" * 70)
|
| 104 |
+
|
| 105 |
+
if __name__ == "__main__":
|
| 106 |
+
test_token_expiry()
|