#!/usr/bin/env python3 """ IMPROVED OAUTH SERVER - Emergency Fix Complete OAuth server with all required endpoints """ from datetime import datetime import json import os import secrets import urllib.parse from flask import Flask, jsonify, request def create_improved_oauth_server(): """Create improved OAuth server with all endpoints""" app = Flask(__name__) app.secret_key = os.getenv("FLASK_SECRET_KEY", "emergency-oauth-secret") # Enhanced services configuration services_config = { "github": { "status": "configured" if os.getenv("GITHUB_CLIENT_ID") else "needs_credentials", "client_id": os.getenv("GITHUB_CLIENT_ID", "github_placeholder_client_id"), "auth_url": "https://github.com/login/oauth/authorize", "scopes": ["repo", "user:email"], }, "google": { "status": "configured" if os.getenv("GOOGLE_CLIENT_ID") else "needs_credentials", "client_id": os.getenv("GOOGLE_CLIENT_ID", "google_placeholder_client_id"), "auth_url": "https://accounts.google.com/o/oauth2/v2/auth", "scopes": ["email", "profile", "https://www.googleapis.com/auth/calendar"], }, "slack": { "status": "configured" if os.getenv("SLACK_CLIENT_ID") else "needs_credentials", "client_id": os.getenv("SLACK_CLIENT_ID", "slack_placeholder_client_id"), "auth_url": "https://slack.com/oauth/v2/authorize", "scopes": ["chat:read", "chat:write", "channels:read"], }, "dropbox": { "status": "configured" if os.getenv("DROPBOX_CLIENT_ID") else "needs_credentials", "client_id": os.getenv("DROPBOX_APP_KEY", "dropbox_placeholder_client_id"), "auth_url": "https://www.dropbox.com/oauth2/authorize", "scopes": [ "files.metadata.read", "files.content.read", "files.content.write", ], }, "trello": { "status": "configured" if os.getenv("TRELLO_CLIENT_ID") else "needs_credentials", "client_id": os.getenv("TRELLO_API_KEY", "trello_placeholder_client_id"), "auth_url": "https://trello.com/1/authorize", "scopes": ["read", "write"], }, } # Health endpoint @app.route("/healthz") def health(): return jsonify( { "status": "ok", "service": "atom-oauth-emergency-fix", "version": "2.0.0-emergency", "timestamp": datetime.now().isoformat(), } ) # Root endpoint @app.route("/") def root(): return jsonify( { "service": "ATOM OAuth Server (Emergency Fix)", "status": "running", "endpoints": [ "/healthz", "/api/auth/oauth-status", "/api/auth/services", "/api/auth/{service}/authorize", "/api/auth/{service}/status", "/api/auth/{service}/callback", ], } ) # OAuth status endpoint @app.route("/api/auth/oauth-status", methods=["GET"]) def oauth_status(): user_id = request.args.get("user_id", "emergency_test_user") results = {} connected_count = 0 needs_credentials_count = 0 for service, config in services_config.items(): status_info = { "ok": True, "service": service, "user_id": user_id, "status": config["status"], "client_id": config["client_id"], "message": f"{service.title()} OAuth is {config['status'].replace('_', ' ')}", } results[service] = status_info if config["status"] == "configured": connected_count += 1 elif "placeholder" in config["client_id"]: needs_credentials_count += 1 return jsonify( { "ok": True, "user_id": user_id, "total_services": len(services_config), "connected_services": connected_count, "services_needing_credentials": needs_credentials_count, "success_rate": f"{connected_count / len(services_config) * 100:.1f}%", "results": results, "timestamp": datetime.now().isoformat(), } ) # Services list endpoint @app.route("/api/auth/services", methods=["GET"]) def oauth_services_list(): return jsonify( { "ok": True, "services": list(services_config.keys()), "total_services": len(services_config), "services_with_real_credentials": len( [ s for s, c in services_config.items() if c.get("client_id") and "placeholder" not in c.get("client_id", "") ] ), "services_needing_credentials": len( [ s for s, c in services_config.items() if "placeholder" in c.get("client_id", "") ] ), "timestamp": datetime.now().isoformat(), } ) # OAuth authorize endpoint (works for all services) @app.route("/api/auth//authorize", methods=["GET"]) def oauth_authorize(service): user_id = request.args.get("user_id") redirect_uri = request.args.get( "redirect_uri", "http://localhost:3000/api/auth/callback" ) if not user_id: return jsonify({"error": "user_id parameter is required"}), 400 if service not in services_config: return jsonify({"error": f"Service {service} not supported"}), 404 config = services_config[service] if "placeholder" in config["client_id"]: return jsonify( { "ok": True, "service": service, "user_id": user_id, "status": "needs_credentials", "message": f"{service.title()} OAuth needs real credentials", "setup_guide": f"Set {service.upper()}_CLIENT_ID and {service.upper()}_CLIENT_SECRET in .env", "credentials": "placeholder", "available_services": list(services_config.keys()), "auth_url": config["auth_url"], "timestamp": datetime.now().isoformat(), } ), 200 # Generate authorization URL for real credentials csrf_token = secrets.token_urlsafe(32) state = f"csrf_token={csrf_token}&service={service}&user_id={user_id}" auth_params = { "client_id": config["client_id"], "redirect_uri": redirect_uri, "response_type": "code", "state": state, "scope": " ".join(config.get("scopes", [])), } if service in ["github"]: auth_params["scope"] = " ".join(config["scopes"]) elif service in ["google", "gmail"]: auth_params.update({"access_type": "offline", "prompt": "consent"}) elif service == "slack": auth_params["scope"] = " ".join(config["scopes"]) auth_url = f"{config['auth_url']}?{urllib.parse.urlencode(auth_params)}" return jsonify( { "ok": True, "service": service, "user_id": user_id, "auth_url": auth_url, "csrf_token": csrf_token, "client_id": config["client_id"], "credentials": "real", "scopes": config.get("scopes", []), "redirect_uri": redirect_uri, "message": f"{service.title()} OAuth authorization URL generated successfully", "timestamp": datetime.now().isoformat(), } ) # OAuth status endpoint (specific service) @app.route("/api/auth//status", methods=["GET"]) def oauth_status_service(service): if service not in services_config: return jsonify({"error": f"Service {service} not supported"}), 404 config = services_config[service] return jsonify( { "ok": True, "service": service, "user_id": request.args.get("user_id", "emergency_test_user"), "status": config["status"], "client_id": config["client_id"], "scopes": config.get("scopes", []), "auth_url": config["auth_url"], "last_check": datetime.now().isoformat(), "message": f"{service.title()} OAuth is {config['status'].replace('_', ' ')}", "timestamp": datetime.now().isoformat(), } ) # OAuth callback endpoint @app.route("/api/auth//callback", methods=["GET", "POST"]) def oauth_callback(service): if service not in services_config: return jsonify({"error": f"Service {service} not supported"}), 404 code = request.args.get("code") state = request.args.get("state") error = request.args.get("error") if error: return jsonify( { "ok": True, "service": service, "error": error, "message": f"{service.title()} OAuth failed with error: {error}", "redirect": f"/settings?service={service}&status=error&error={error}", "timestamp": datetime.now().isoformat(), } ) return jsonify( { "ok": True, "service": service, "code": code, "state": state, "message": f"{service.title()} OAuth callback received successfully", "redirect": f"/settings?service={service}&status=connected", "token_exchange": "Use this code to exchange for access tokens", "timestamp": datetime.now().isoformat(), } ) return app if __name__ == "__main__": app = create_improved_oauth_server() print("🚨 ATOM EMERGENCY OAUTH SERVER") print("=" * 45) print("🌐 Server starting on http://localhost:5058") print("šŸ“‹ Available OAuth Services:") print(" - github") print(" - google") print(" - slack") print("šŸ“‹ Available Endpoints:") print(" - GET /healthz") print(" - GET /api/auth/oauth-status") print(" - GET /api/auth/services") print(" - GET /api/auth/{service}/authorize") print(" - GET /api/auth/{service}/status") print(" - GET/POST /api/auth/{service}/callback") print("=" * 45) try: app.run(host="0.0.0.0", port=5058, debug=False, threaded=True) except KeyboardInterrupt: print("\nšŸ›‘ Server stopped by user") except Exception as e: print(f"āŒ Server error: {e}")