#!/usr/bin/env python3 """ Script to configure LinkedIn (OIDC) authentication for self-hosted Supabase. This script updates your .env file or docker-compose.yml with the necessary GoTrue environment variables. """ import os import sys from pathlib import Path # ==================== CONFIGURATION ==================== # TODO: Fill in your LinkedIn credentials below LINKEDIN_CLIENT_ID = "your-linkedin-client-id" LINKEDIN_CLIENT_SECRET = "your-linkedin-client-secret" # Your Supabase instance URL (where your self-hosted instance is accessible) SUPABASE_URL = "https://your-supabase-domain.com" # e.g., https://supabase.example.com # Path to your Supabase docker-compose directory (where .env or docker-compose.yml is located) DOCKER_COMPOSE_DIR = "/path/to/your/supabase" # e.g., /home/user/supabase # ======================================================= def validate_config(): """Validate that all required configuration is set.""" errors = [] if LINKEDIN_CLIENT_ID.startswith("your-"): errors.append("LINKEDIN_CLIENT_ID") if LINKEDIN_CLIENT_SECRET.startswith("your-"): errors.append("LINKEDIN_CLIENT_SECRET") if SUPABASE_URL.startswith("https://your-"): errors.append("SUPABASE_URL") if DOCKER_COMPOSE_DIR.startswith("/path/to/"): errors.append("DOCKER_COMPOSE_DIR") if errors: print("āŒ Error: Please update the following configuration variables in this script:") for var in errors: print(f" - {var}") sys.exit(1) def find_env_file(): """Find the .env file in the docker-compose directory.""" compose_dir = Path(DOCKER_COMPOSE_DIR) if not compose_dir.exists(): print(f"āŒ Error: Directory not found: {DOCKER_COMPOSE_DIR}") sys.exit(1) # Look for common .env file locations env_files = [ compose_dir / ".env", compose_dir / "docker" / ".env", compose_dir / ".env.local", ] for env_file in env_files: if env_file.exists(): return env_file return None def update_env_file(env_file): """Update the .env file with LinkedIn OAuth configuration.""" # LinkedIn OAuth configuration for GoTrue linkedin_config = f""" # LinkedIn OAuth Configuration (added by setup script) GOTRUE_EXTERNAL_LINKEDIN_ENABLED=true GOTRUE_EXTERNAL_LINKEDIN_CLIENT_ID={LINKEDIN_CLIENT_ID} GOTRUE_EXTERNAL_LINKEDIN_SECRET={LINKEDIN_CLIENT_SECRET} GOTRUE_EXTERNAL_LINKEDIN_REDIRECT_URI={SUPABASE_URL}/auth/v1/callback """ # Read existing content if env_file: with open(env_file, 'r') as f: content = f.read() # Check if LinkedIn config already exists if "GOTRUE_EXTERNAL_LINKEDIN_ENABLED" in content: print(f"āš ļø LinkedIn OAuth configuration already exists in {env_file}") print(" Please update it manually or remove the existing lines first.") return False # Backup original file backup_file = env_file.with_suffix('.env.backup') with open(backup_file, 'w') as f: f.write(content) print(f"šŸ“‹ Backup created: {backup_file}") # Append LinkedIn config with open(env_file, 'a') as f: f.write(linkedin_config) print(f"āœ… LinkedIn OAuth configuration added to {env_file}") return True return False def create_env_snippet(): """Create a snippet file if no .env file is found.""" snippet_file = Path(DOCKER_COMPOSE_DIR) / "linkedin_oauth_snippet.env" linkedin_config = f"""# LinkedIn OAuth Configuration for GoTrue # Add these lines to your .env file or docker-compose.yml environment section GOTRUE_EXTERNAL_LINKEDIN_ENABLED=true GOTRUE_EXTERNAL_LINKEDIN_CLIENT_ID={LINKEDIN_CLIENT_ID} GOTRUE_EXTERNAL_LINKEDIN_SECRET={LINKEDIN_CLIENT_SECRET} GOTRUE_EXTERNAL_LINKEDIN_REDIRECT_URI={SUPABASE_URL}/auth/v1/callback """ with open(snippet_file, 'w') as f: f.write(linkedin_config) print(f"šŸ“„ Created configuration snippet: {snippet_file}") print(" Copy these variables to your .env file or docker-compose.yml") return True def print_next_steps(): """Print instructions for completing the setup.""" print("\n" + "="*60) print("āœ… Configuration complete!") print("="*60) print("\nNext steps:\n") print("1. Restart your Supabase services:") print(f" cd {DOCKER_COMPOSE_DIR}") print(" docker-compose down") print(" docker-compose up -d") print() print("2. Add redirect URL in LinkedIn Developer Portal:") print(f" {SUPABASE_URL}/auth/v1/callback") print() print("3. Test the authentication in your application") print() print("4. Check GoTrue logs for any errors:") print(" docker-compose logs -f auth") print() def main(): """Main function.""" print("šŸ”§ Configuring LinkedIn OAuth for self-hosted Supabase") print("="*60) validate_config() env_file = find_env_file() if env_file: print(f"šŸ“ Found .env file: {env_file}") if update_env_file(env_file): print_next_steps() else: print("\nāš ļø Please update your configuration manually.") else: print("āš ļø No .env file found in the docker-compose directory") create_env_snippet() print_next_steps() if __name__ == "__main__": main()