| |
| """ |
| ATOM Platform - OAuth Setup and Configuration Script |
| Complete OAuth setup for production deployment |
| """ |
|
|
| import json |
| import os |
| from pathlib import Path |
| import sys |
| from typing import Dict, List, Optional, Tuple |
| import webbrowser |
| import requests |
|
|
|
|
| class OAuthSetup: |
| """OAuth setup and configuration manager""" |
|
|
| def __init__(self): |
| self.base_dir = Path(__file__).parent |
| self.oauth_server_url = "http://localhost:5058" |
| self.backend_url = "http://localhost:8000" |
|
|
| |
| self.services = { |
| "github": { |
| "name": "GitHub", |
| "setup_url": "https://github.com/settings/applications/new", |
| "callback_url": f"{self.oauth_server_url}/api/auth/github/callback", |
| "scopes": ["repo", "user:email", "read:org"], |
| "required": True, |
| "env_vars": ["GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET"], |
| "setup_instructions": """ |
| 1. Go to GitHub Settings → Developer settings → OAuth Apps |
| 2. Click "New OAuth App" |
| 3. Application name: "ATOM Platform" |
| 4. Homepage URL: http://localhost:3000 (or your domain) |
| 5. Authorization callback URL: {callback_url} |
| 6. Click "Register application" |
| 7. Copy Client ID and Client Secret |
| """.strip(), |
| }, |
| "google": { |
| "name": "Google", |
| "setup_url": "https://console.developers.google.com/apis/credentials", |
| "callback_url": f"{self.oauth_server_url}/api/auth/google/callback", |
| "scopes": [ |
| "email", |
| "profile", |
| "https://www.googleapis.com/auth/calendar", |
| "https://www.googleapis.com/auth/gmail.readonly", |
| "https://www.googleapis.com/auth/drive", |
| ], |
| "required": True, |
| "env_vars": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET"], |
| "setup_instructions": """ |
| 1. Go to Google Cloud Console |
| 2. Create a new project or select existing |
| 3. Enable APIs: Calendar, Gmail, Drive |
| 4. Go to Credentials → Create Credentials → OAuth 2.0 Client IDs |
| 5. Application type: Web application |
| 6. Name: "ATOM Platform" |
| 7. Authorized redirect URIs: {callback_url} |
| 8. Click "Create" |
| 9. Copy Client ID and Client Secret |
| """.strip(), |
| }, |
| "slack": { |
| "name": "Slack", |
| "setup_url": "https://api.slack.com/apps", |
| "callback_url": f"{self.oauth_server_url}/api/auth/slack/callback", |
| "scopes": ["chat:write", "channels:read", "groups:read", "users:read"], |
| "required": True, |
| "env_vars": ["SLACK_CLIENT_ID", "SLACK_CLIENT_SECRET"], |
| "setup_instructions": """ |
| 1. Go to Slack API: Create New App |
| 2. Choose "From scratch" |
| 3. App name: "ATOM Platform", Workspace: your workspace |
| 4. Go to OAuth & Permissions |
| 5. Add Redirect URLs: {callback_url} |
| 6. Add Bot Token Scopes: chat:write, channels:read, groups:read, users:read |
| 7. Install app to workspace |
| 8. Copy OAuth Credentials: Client ID and Client Secret |
| """.strip(), |
| }, |
| "dropbox": { |
| "name": "Dropbox", |
| "setup_url": "https://www.dropbox.com/developers/apps", |
| "callback_url": f"{self.oauth_server_url}/api/auth/dropbox/callback", |
| "scopes": [ |
| "files.metadata.read", |
| "files.content.read", |
| "files.content.write", |
| ], |
| "required": False, |
| "env_vars": ["DROPBOX_CLIENT_ID", "DROPBOX_CLIENT_SECRET"], |
| "setup_instructions": """ |
| 1. Go to Dropbox Developer Console |
| 2. Create app → Scoped access |
| 3. Choose access: App folder or Full Dropbox |
| 4. App name: "ATOM Platform" |
| 5. Go to Permissions tab, enable: files.metadata.read, files.content.read, files.content.write |
| 6. Go to Settings tab |
| 7. OAuth 2 → Redirect URIs: {callback_url} |
| 8. Copy App key (Client ID) and App secret (Client Secret) |
| """.strip(), |
| }, |
| "trello": { |
| "name": "Trello", |
| "setup_url": "https://trello.com/power-ups/admin", |
| "callback_url": f"{self.oauth_server_url}/api/auth/trello/callback", |
| "scopes": ["read", "write"], |
| "required": False, |
| "env_vars": ["TRELLO_CLIENT_ID", "TRELLO_CLIENT_SECRET"], |
| "setup_instructions": """ |
| 1. Go to Trello Developer API Keys |
| 2. Click "Generate a new API key" |
| 3. Application name: "ATOM Platform" |
| 4. Description: "Workflow automation platform" |
| 5. Accept terms and generate |
| 6. Copy API Key (Client ID) |
| 7. To get Secret: Click "Token" next to your API key |
| 8. Generate a new token with read, write permissions |
| 9. Copy Token (Client Secret) |
| """.strip(), |
| }, |
| } |
|
|
| def check_current_status(self) -> Dict: |
| """Check current OAuth configuration status""" |
| print("🔍 Checking current OAuth status...") |
|
|
| status = {} |
| try: |
| response = requests.get( |
| f"{self.oauth_server_url}/api/auth/services", timeout=10 |
| ) |
| if response.status_code == 200: |
| data = response.json() |
| status["total_services"] = data.get("total_services", 0) |
| status["configured_services"] = data.get( |
| "services_with_real_credentials", 0 |
| ) |
| status["needs_credentials"] = data.get( |
| "services_needing_credentials", 0 |
| ) |
|
|
| |
| for service in self.services.keys(): |
| try: |
| service_response = requests.get( |
| f"{self.oauth_server_url}/api/auth/{service}/status", |
| timeout=5, |
| ) |
| if service_response.status_code == 200: |
| service_data = service_response.json() |
| status[service] = { |
| "configured": service_data.get("status") |
| == "configured", |
| "client_id": service_data.get("client_id", ""), |
| "message": service_data.get("message", ""), |
| } |
| except: |
| status[service] = { |
| "configured": False, |
| "error": "Service not reachable", |
| } |
| else: |
| print(" ❌ OAuth server not responding") |
| except Exception as e: |
| print(f" ❌ Error checking OAuth status: {e}") |
|
|
| return status |
|
|
| def print_status_report(self): |
| """Print comprehensive OAuth status report""" |
| print("\n" + "=" * 60) |
| print("📊 ATOM PLATFORM - OAUTH CONFIGURATION STATUS") |
| print("=" * 60) |
|
|
| status = self.check_current_status() |
|
|
| if not status: |
| print("❌ Could not retrieve OAuth status") |
| return |
|
|
| print(f"\n📋 OVERVIEW:") |
| print(f" Total Services: {status.get('total_services', 0)}") |
| print(f" Configured: {status.get('configured_services', 0)}") |
| print(f" Needs Credentials: {status.get('needs_credentials', 0)}") |
|
|
| print(f"\n🔧 SERVICE STATUS:") |
| for service_name, service_config in self.services.items(): |
| service_status = status.get(service_name, {}) |
| if service_status.get("configured"): |
| print(f" ✅ {service_config['name']:12} - Configured") |
| else: |
| requirement = "REQUIRED" if service_config["required"] else "Optional" |
| print( |
| f" ❌ {service_config['name']:12} - Not configured ({requirement})" |
| ) |
|
|
| def setup_service(self, service_name: str) -> bool: |
| """Setup a specific OAuth service""" |
| if service_name not in self.services: |
| print(f"❌ Unknown service: {service_name}") |
| return False |
|
|
| service_config = self.services[service_name] |
|
|
| print(f"\n🔐 Setting up {service_config['name']} OAuth...") |
| print("=" * 50) |
|
|
| |
| instructions = service_config["setup_instructions"].format( |
| callback_url=service_config["callback_url"] |
| ) |
| print(f"\n📚 SETUP INSTRUCTIONS:\n{instructions}") |
|
|
| |
| print(f"\n🌐 Opening setup page in browser...") |
| try: |
| webbrowser.open(service_config["setup_url"]) |
| except: |
| print( |
| f" ⚠️ Could not open browser. Please visit: {service_config['setup_url']}" |
| ) |
|
|
| |
| print(f"\n🔑 Please enter your {service_config['name']} credentials:") |
| client_id = input(f" Client ID: ").strip() |
| client_secret = input(f" Client Secret: ").strip() |
|
|
| if not client_id or not client_secret: |
| print(" ❌ Credentials cannot be empty") |
| return False |
|
|
| |
| env_updated = self._update_environment(service_name, client_id, client_secret) |
|
|
| if env_updated: |
| print(f" ✅ {service_config['name']} credentials saved") |
| print(f" 🔄 Please restart the OAuth server to apply changes") |
| return True |
| else: |
| print(f" ❌ Failed to save credentials") |
| return False |
|
|
| def _update_environment( |
| self, service_name: str, client_id: str, client_secret: str |
| ) -> bool: |
| """Update environment variables with OAuth credentials""" |
| env_vars = self.services[service_name]["env_vars"] |
|
|
| |
| env_files = [".env", "real_credentials.env", ".env.production"] |
|
|
| for env_file in env_files: |
| file_path = self.base_dir / env_file |
| if file_path.exists(): |
| return self._update_env_file( |
| file_path, env_vars[0], client_id, env_vars[1], client_secret |
| ) |
|
|
| |
| default_env = self.base_dir / ".env" |
| return self._update_env_file( |
| default_env, env_vars[0], client_id, env_vars[1], client_secret |
| ) |
|
|
| def _update_env_file( |
| self, |
| file_path: Path, |
| client_id_var: str, |
| client_id: str, |
| client_secret_var: str, |
| client_secret: str, |
| ) -> bool: |
| """Update or create environment file""" |
| try: |
| if file_path.exists(): |
| |
| content = file_path.read_text() |
| lines = content.split("\n") |
|
|
| |
| updated_lines = [] |
| client_id_found = False |
| client_secret_found = False |
|
|
| for line in lines: |
| if line.startswith(f"{client_id_var}="): |
| updated_lines.append(f"{client_id_var}={client_id}") |
| client_id_found = True |
| elif line.startswith(f"{client_secret_var}="): |
| updated_lines.append(f"{client_secret_var}={client_secret}") |
| client_secret_found = True |
| else: |
| updated_lines.append(line) |
|
|
| |
| if not client_id_found: |
| updated_lines.append(f"{client_id_var}={client_id}") |
| if not client_secret_found: |
| updated_lines.append(f"{client_secret_var}={client_secret}") |
|
|
| content = "\n".join(updated_lines) |
| else: |
| |
| content = f"""# ATOM Platform - OAuth Configuration |
| {client_id_var}={client_id} |
| {client_secret_var}={client_secret} |
| """ |
|
|
| file_path.write_text(content) |
| print(f" ✅ Updated: {file_path.name}") |
| return True |
|
|
| except Exception as e: |
| print(f" ❌ Error updating {file_path}: {e}") |
| return False |
|
|
| def test_oauth_flow(self, service_name: str) -> bool: |
| """Test OAuth flow for a service""" |
| if service_name not in self.services: |
| print(f"❌ Unknown service: {service_name}") |
| return False |
|
|
| print(f"\n🧪 Testing {self.services[service_name]['name']} OAuth flow...") |
|
|
| try: |
| |
| response = requests.get( |
| f"{self.oauth_server_url}/api/auth/{service_name}/status", timeout=10 |
| ) |
|
|
| if response.status_code != 200: |
| print(f" ❌ Service status check failed: {response.status_code}") |
| return False |
|
|
| service_data = response.json() |
|
|
| if service_data.get("status") != "configured": |
| print(f" ❌ Service not configured: {service_data.get('message')}") |
| return False |
|
|
| |
| auth_response = requests.get( |
| f"{self.oauth_server_url}/api/auth/{service_name}/authorize", |
| params={"user_id": "test_user"}, |
| timeout=10, |
| ) |
|
|
| if auth_response.status_code == 200: |
| auth_data = auth_response.json() |
| if auth_data.get("credentials") == "real": |
| print(f" ✅ OAuth flow working - Authorization URL generated") |
| print(f" 🔗 Auth URL: {auth_data.get('auth_url')}") |
| return True |
| else: |
| print(f" ❌ Using placeholder credentials") |
| return False |
| else: |
| print(f" ❌ Authorization failed: {auth_response.status_code}") |
| return False |
|
|
| except Exception as e: |
| print(f" ❌ OAuth test failed: {e}") |
| return False |
|
|
| def setup_all_required(self) -> bool: |
| """Setup all required OAuth services""" |
| print("\n🚀 Setting up all required OAuth services...") |
|
|
| required_services = [ |
| name for name, config in self.services.items() if config["required"] |
| ] |
| success_count = 0 |
|
|
| for service_name in required_services: |
| if self.setup_service(service_name): |
| success_count += 1 |
| else: |
| print(f" ⚠️ Failed to setup {service_name}") |
|
|
| print( |
| f"\n📊 Setup completed: {success_count}/{len(required_services)} required services configured" |
| ) |
| return success_count == len(required_services) |
|
|
| def generate_setup_guide(self): |
| """Generate comprehensive setup guide""" |
| guide_file = self.base_dir / "OAUTH_SETUP_GUIDE.md" |
|
|
| guide_content = f"""# ATOM Platform - OAuth Setup Guide |
| |
| ## Overview |
| This guide will help you configure OAuth integrations for the ATOM Platform. |
| |
| ## Prerequisites |
| - Running ATOM Platform services |
| - Admin access to the services you want to integrate |
| |
| ## Service Configuration |
| |
| """ |
|
|
| for service_name, service_config in self.services.items(): |
| requirement = "**REQUIRED**" if service_config["required"] else "Optional" |
| instructions = service_config["setup_instructions"].format( |
| callback_url=service_config["callback_url"] |
| ) |
|
|
| guide_content += f"""### {service_config["name"]} ({requirement}) |
| |
| {instructions} |
| |
| **Environment Variables:** |
| - `{service_config["env_vars"][0]}` = Your Client ID |
| - `{service_config["env_vars"][1]}` = Your Client Secret |
| |
| **Callback URL:** `{service_config["callback_url"]}` |
| |
| --- |
| |
| """ |
|
|
| guide_content += """ |
| ## Verification Steps |
| |
| 1. **Check Current Status:** |
| ```bash |
| python setup_oauth.py --status |
| ``` |
| |
| 2. **Setup Individual Service:** |
| ```bash |
| python setup_oauth.py --setup github |
| ``` |
| |
| 3. **Setup All Required Services:** |
| ```bash |
| python setup_oauth.py --setup-all |
| ``` |
| |
| 4. **Test OAuth Flow:** |
| ```bash |
| python setup_oauth.py --test github |
| ``` |
| |
| ## Troubleshooting |
| |
| ### Common Issues |
| |
| 1. **"Service not configured"** |
| - Check that environment variables are set |
| - Restart OAuth server after setting variables |
| |
| 2. **"Invalid redirect URI"** |
| - Ensure callback URL matches exactly |
| - Include http:// or https:// prefix |
| |
| 3. **"Invalid client credentials"** |
| - Verify Client ID and Client Secret |
| - Check for typos or extra spaces |
| |
| ### Support |
| For additional help, check the ATOM Platform documentation or contact support. |
| """ |
|
|
| guide_file.write_text(guide_content) |
| print(f"✅ Setup guide generated: {guide_file.name}") |
|
|
| def run_interactive_setup(self): |
| """Run interactive OAuth setup""" |
| print("🚀 ATOM Platform - Interactive OAuth Setup") |
| print("=" * 50) |
|
|
| while True: |
| print("\n📋 OPTIONS:") |
| print("1. Check OAuth status") |
| print("2. Setup specific service") |
| print("3. Setup all required services") |
| print("4. Test OAuth flow") |
| print("5. Generate setup guide") |
| print("6. Exit") |
|
|
| choice = input("\nEnter your choice (1-6): ").strip() |
|
|
| if choice == "1": |
| self.print_status_report() |
| elif choice == "2": |
| print("\nAvailable services:") |
| for i, (name, config) in enumerate(self.services.items(), 1): |
| requirement = "REQUIRED" if config["required"] else "Optional" |
| print(f" {i}. {config['name']} ({requirement})") |
|
|
| service_choice = input("\nEnter service number or name: ").strip() |
| if service_choice.isdigit(): |
| service_index = int(service_choice) - 1 |
| service_names = list(self.services.keys()) |
| if 0 <= service_index < len(service_names): |
| self.setup_service(service_names[service_index]) |
| else: |
| print("❌ Invalid service number") |
| else: |
| self.setup_service(service_choice.lower()) |
| elif choice == "3": |
| self.setup_all_required() |
| elif choice == "4": |
| service_name = input("Enter service name to test: ").strip().lower() |
| self.test_oauth_flow(service_name) |
| elif choice == "5": |
| self.generate_setup_guide() |
| elif choice == "6": |
| print("👋 Goodbye!") |
| break |
| else: |
| print("❌ Invalid choice. Please enter 1-6.") |
|
|
| def run_cli_setup(self, args): |
| """Run CLI-based setup""" |
| if "--status" in args: |
| self.print_status_report() |
| elif "--setup" in args: |
| if len(args) > 2: |
| self.setup_service(args[2]) |
| else: |
| print("❌ Please specify service: --setup [service_name]") |
| elif "--setup-all" in args: |
| self.setup_all_required() |
| elif "--test" in args: |
| if len(args) > 2: |
| self.test_oauth_flow(args[2]) |
| else: |
| print("❌ Please specify service: --test [service_name]") |
| elif "--guide" in args: |
| self.generate_setup_guide() |
| else: |
| print("Usage: python setup_oauth.py [OPTION]") |
| print("Options:") |
| print(" --status Check OAuth configuration status") |
| print(" --setup SERVICE Setup specific OAuth service") |
| print(" --setup-all Setup all required OAuth services") |
| print(" --test SERVICE Test OAuth flow for service") |
| print(" --guide Generate setup guide") |
| print(" --interactive Run interactive setup") |
|
|
|
|
| def main(): |
| """Main function""" |
| setup = OAuthSetup() |
|
|
| if len(sys.argv) > 1: |
| setup.run_cli_setup(sys.argv) |
| else: |
| setup.run_interactive_setup() |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|