#!/usr/bin/env python3 """ 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" # OAuth service configuration 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 ) # Check individual service status 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) # Show setup instructions instructions = service_config["setup_instructions"].format( callback_url=service_config["callback_url"] ) print(f"\n📚 SETUP INSTRUCTIONS:\n{instructions}") # Open setup URL in browser 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']}" ) # Get credentials from user 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 # Update environment 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"] # Try to update .env file 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 ) # Create new .env file if none exists 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(): # Read existing content content = file_path.read_text() lines = content.split("\n") # Update existing variables or add new ones 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) # Add missing variables 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: # Create new file 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: # Check service status 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 # Try to generate authorization URL 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()