<# .SYNOPSIS Setup Claude Authentication on Windows Server using Claude Pro subscription .DESCRIPTION This script helps authenticate Claude Agent SDK using Claude Pro/Max subscription. Two methods are supported: 1. Direct login on server (opens browser for authentication) 2. Copy credentials from development machine .PARAMETER Method Authentication method: 'login' or 'copy' (default: login) .PARAMETER CredentialsPath Path to credentials file (for 'copy' method) .EXAMPLE .\Setup-ClaudeAuth.ps1 Interactive login on server (opens browser) .EXAMPLE .\Setup-ClaudeAuth.ps1 -Method copy -CredentialsPath "C:\path\to\credentials.json" Copy credentials from file .NOTES Author: ROA2WEB Team Requires: Claude Pro/Max subscription, Python 3.11+ #> [CmdletBinding()] param( [ValidateSet('login', 'copy')] [string]$Method = 'login', [string]$CredentialsPath = "" ) $ErrorActionPreference = "Stop" # ============================================================================= # HELPER FUNCTIONS # ============================================================================= function Write-Step { param([string]$Message) Write-Host "`n[*] $Message" -ForegroundColor Cyan } function Write-Success { param([string]$Message) Write-Host " [OK] $Message" -ForegroundColor Green } function Write-Error { param([string]$Message) Write-Host " [ERROR] $Message" -ForegroundColor Red } function Write-Warning { param([string]$Message) Write-Host " [WARN] $Message" -ForegroundColor Yellow } function Test-ClaudeInstalled { Write-Step "Checking for Claude Code installation..." try { $result = & claude-code --version 2>&1 if ($LASTEXITCODE -eq 0) { Write-Success "Claude Code is installed: $result" return $true } } catch { Write-Warning "Claude Code CLI not found" return $false } return $false } function Install-ClaudeCode { Write-Step "Installing Claude Code CLI..." try { # Check if npm is available $npmVersion = & npm --version 2>&1 if ($LASTEXITCODE -ne 0) { Write-Error "npm is not installed. Please install Node.js first." Write-Host " Download from: https://nodejs.org/" -ForegroundColor Yellow throw "npm not found" } Write-Success "npm found: v$npmVersion" # Install claude-code globally Write-Step "Installing @anthropic-ai/claude-code via npm..." & npm install -g @anthropic-ai/claude-code if ($LASTEXITCODE -eq 0) { Write-Success "Claude Code CLI installed successfully" return $true } else { throw "npm install failed" } } catch { Write-Error "Failed to install Claude Code CLI: $_" return $false } } function Invoke-ClaudeLogin { Write-Step "Initiating Claude authentication..." Write-Host "`n" + ("=" * 60) -ForegroundColor Yellow Write-Host " IMPORTANT: Browser Authentication Required" -ForegroundColor Yellow Write-Host ("=" * 60) -ForegroundColor Yellow Write-Host "" Write-Host " 1. A browser window will open" -ForegroundColor White Write-Host " 2. Log in with your Claude Pro/Max account" -ForegroundColor White Write-Host " 3. Authorize the application" -ForegroundColor White Write-Host " 4. Return to this window after authentication" -ForegroundColor White Write-Host "" Write-Host ("=" * 60) -ForegroundColor Yellow Write-Host "" $response = Read-Host "Press ENTER to open browser and continue (or Ctrl+C to cancel)" try { Write-Step "Opening browser for authentication..." & claude-code login if ($LASTEXITCODE -eq 0) { Write-Success "Authentication successful!" return $true } else { Write-Error "Authentication failed or was cancelled" return $false } } catch { Write-Error "Failed to authenticate: $_" return $false } } function Find-CredentialsInPackage { Write-Step "Searching for credentials in deployment package..." # Try to find credentials in common locations $searchPaths = @( # If running from scripts/ subdirectory (Join-Path $PSScriptRoot "..\claude-credentials.json"), # If running from package root (Join-Path $PSScriptRoot "claude-credentials.json"), # If in temp deployment location "C:\Temp\telegram-bot-deploy\claude-credentials.json", "C:\Temp\telegram-bot-updated\claude-credentials.json", # If already in installation directory "C:\inetpub\wwwroot\roa2web\telegram-bot\claude-credentials.json" ) foreach ($path in $searchPaths) { $resolved = [System.IO.Path]::GetFullPath($path) if (Test-Path $resolved) { Write-Success "Found credentials at: $resolved" return $resolved } } Write-Warning "No credentials file found in deployment package" return $null } function Copy-CredentialsFile { param([string]$SourcePath) Write-Step "Copying credentials from: $SourcePath" if (-not (Test-Path $SourcePath)) { Write-Error "Credentials file not found: $SourcePath" return $false } try { # Determine credentials directory (correct location: %USERPROFILE%\.claude\) $credentialsDir = Join-Path $env:USERPROFILE ".claude" $credentialsFile = Join-Path $credentialsDir ".credentials.json" # Create directory if needed if (-not (Test-Path $credentialsDir)) { New-Item -ItemType Directory -Path $credentialsDir -Force | Out-Null Write-Success "Created credentials directory: $credentialsDir" } # Copy credentials file Copy-Item -Path $SourcePath -Destination $credentialsFile -Force Write-Success "Credentials copied successfully" Write-Success "Location: $credentialsFile" return $true } catch { Write-Error "Failed to copy credentials: $_" return $false } } function Test-ClaudeAuth { Write-Step "Testing Claude authentication..." # Check both possible locations $possibleLocations = @( (Join-Path $env:USERPROFILE ".claude\.credentials.json"), # Correct location (Join-Path $env:APPDATA "claude\credentials.json") # Alternative location ) $credentialsFile = $null foreach ($location in $possibleLocations) { if (Test-Path $location) { $credentialsFile = $location break } } if (-not $credentialsFile) { Write-Warning "Credentials file not found at any expected location" Write-Host " Checked: $($possibleLocations -join ', ')" -ForegroundColor Gray return $false } try { # Read credentials file $credentials = Get-Content $credentialsFile -Raw | ConvertFrom-Json if ($credentials -and $credentials.sessionKey) { Write-Success "Credentials file found and valid" Write-Success "Location: $credentialsFile" Write-Success "Session key: $($credentials.sessionKey.Substring(0, 20))..." return $true } else { Write-Warning "Credentials file exists but appears invalid" return $false } } catch { Write-Warning "Could not validate credentials: $_" return $false } } function Update-EnvFile { Write-Step "Updating .env file..." $envPath = "C:\inetpub\wwwroot\roa2web\telegram-bot\.env" if (-not (Test-Path $envPath)) { Write-Warning ".env file not found at: $envPath" Write-Host " Please create it manually or run Install-TelegramBot.ps1 first" -ForegroundColor Yellow return } try { $envContent = Get-Content $envPath -Raw # Check if CLAUDE_API_KEY is set if ($envContent -match "^CLAUDE_API_KEY=.+$" -and $envContent -notmatch "^CLAUDE_API_KEY=\s*$") { Write-Success ".env already has CLAUDE_API_KEY set" Write-Host " Using API key authentication (takes precedence over browser login)" -ForegroundColor Gray } else { Write-Success ".env will use Claude Pro subscription (browser login)" Write-Host " No CLAUDE_API_KEY needed!" -ForegroundColor Green } } catch { Write-Warning "Could not read .env file: $_" } } function Show-Summary { Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan Write-Host " CLAUDE AUTHENTICATION SETUP COMPLETE" -ForegroundColor Green Write-Host ("=" * 60) -ForegroundColor Cyan # Check both possible locations $possibleLocations = @( (Join-Path $env:USERPROFILE ".claude\.credentials.json"), (Join-Path $env:APPDATA "claude\credentials.json") ) $credentialsFile = $null foreach ($location in $possibleLocations) { if (Test-Path $location) { $credentialsFile = $location break } } if (-not $credentialsFile) { $credentialsFile = Join-Path $env:USERPROFILE ".claude\.credentials.json" # Default expected location } Write-Host "`nAuthentication Details:" -ForegroundColor Yellow Write-Host " Method: Claude Pro/Max Subscription (Browser Login)" Write-Host " Credentials File: $credentialsFile" Write-Host " Status: $(if (Test-Path $credentialsFile) { 'Authenticated ✓' } else { 'Not Found' })" Write-Host "`nNext Steps:" -ForegroundColor Yellow Write-Host " 1. Verify .env file: C:\inetpub\wwwroot\roa2web\telegram-bot\.env" Write-Host " - Remove or leave empty: CLAUDE_API_KEY=" Write-Host " 2. Restart Telegram bot service:" Write-Host " cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts" Write-Host " .\Restart-TelegramBot.ps1" Write-Host " 3. Check logs for 'Using claude-code login' message:" Write-Host " Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log -Tail 50" Write-Host "`nTroubleshooting:" -ForegroundColor Yellow Write-Host " - If authentication fails, re-run: .\Setup-ClaudeAuth.ps1" Write-Host " - Check credentials: Get-Content '$credentialsFile'" Write-Host " - Credentials expire after ~30 days (re-authenticate when needed)" Write-Host " - Expected location: %USERPROFILE%\.claude\.credentials.json" Write-Host "`n" + ("=" * 60) -ForegroundColor Cyan } # ============================================================================= # MAIN SETUP FLOW # ============================================================================= function Main { Write-Host @" ==================================================================== ROA2WEB Telegram Bot - Claude Authentication Setup Configure Claude Pro/Max subscription authentication ==================================================================== "@ -ForegroundColor Cyan try { # First, check if credentials exist in deployment package $packageCredentials = Find-CredentialsInPackage if ($packageCredentials -and $Method -eq 'login') { Write-Host "`n" + ("=" * 60) -ForegroundColor Green Write-Host " CREDENTIALS FOUND IN DEPLOYMENT PACKAGE!" -ForegroundColor Green Write-Host ("=" * 60) -ForegroundColor Green Write-Host "" Write-Host "Found credentials at: $packageCredentials" -ForegroundColor Cyan Write-Host "" $usePackage = Read-Host "Use these credentials? (Y/N)" if ($usePackage -eq "Y" -or $usePackage -eq "y") { Write-Host "`nUsing credentials from deployment package..." -ForegroundColor Yellow $copySuccess = Copy-CredentialsFile -SourcePath $packageCredentials if (-not $copySuccess) { throw "Failed to copy credentials from package" } # Skip other methods $Method = 'package' } else { Write-Host "Proceeding with browser login..." -ForegroundColor Gray } } if ($Method -eq 'login') { # Method 1: Direct login on server Write-Host "Method: Direct Browser Login" -ForegroundColor Yellow # Check if claude-code is installed $isInstalled = Test-ClaudeInstalled if (-not $isInstalled) { Write-Step "Claude Code CLI not found. Installing..." $installed = Install-ClaudeCode if (-not $installed) { throw "Failed to install Claude Code CLI" } } # Perform login $loginSuccess = Invoke-ClaudeLogin if (-not $loginSuccess) { throw "Authentication failed" } } elseif ($Method -eq 'copy') { # Method 2: Copy credentials from file Write-Host "Method: Copy Credentials from File" -ForegroundColor Yellow # If no path provided, try to find automatically if (-not $CredentialsPath) { $autoFound = Find-CredentialsInPackage if ($autoFound) { Write-Host "`nFound credentials in package: $autoFound" -ForegroundColor Green $useAuto = Read-Host "Use this file? (Y/N)" if ($useAuto -eq "Y" -or $useAuto -eq "y") { $CredentialsPath = $autoFound } else { $CredentialsPath = Read-Host "Enter full path to credentials.json" } } else { $CredentialsPath = Read-Host "Enter full path to credentials.json" } } $copySuccess = Copy-CredentialsFile -SourcePath $CredentialsPath if (-not $copySuccess) { throw "Failed to copy credentials" } } # Test authentication $authValid = Test-ClaudeAuth if (-not $authValid) { Write-Warning "Could not validate authentication. Service may still work." } # Update .env file Update-EnvFile # Show summary Show-Summary Write-Host "`nSetup completed successfully!" -ForegroundColor Green } catch { Write-Host "`n[SETUP FAILED] $_" -ForegroundColor Red Write-Host $_.ScriptStackTrace -ForegroundColor Red exit 1 } } # Run main setup Main