Public/Connect-OnePAM.ps1
|
function Connect-OnePAM { <# .SYNOPSIS Authenticates to OnePAM using the OAuth2 Device Code flow. .DESCRIPTION Initiates a device code flow, displays a verification URL and user code, then polls until the user completes browser-based authorization. The resulting access and refresh tokens are saved to ~/.onepam/token.json. .PARAMETER ApiBase Override the API base URL (default: from config or https://onepam.com). .EXAMPLE Connect-OnePAM .EXAMPLE Connect-OnePAM -ApiBase "https://my-onepam.example.com" #> [CmdletBinding()] param( [string]$ApiBase ) $cfg = Get-OpConfig $baseUrl = if ($ApiBase) { $ApiBase } else { $cfg.api_base } Assert-OpValidApiBase -Url $baseUrl $codeUri = "$baseUrl/api/v1/auth/device/code" $codeBody = @{ client_id = 'onepam-cli' scope = 'ssh database resources sessions' } try { $codeResp = Invoke-RestMethod -Uri $codeUri -Method Post -Body $codeBody ` -ContentType 'application/x-www-form-urlencoded' ` -UserAgent "onepam-powershell/$script:ModuleVersion" ` -ErrorAction Stop } catch { throw "Failed to start device code flow: $_" } $deviceCode = $codeResp.device_code $userCode = $codeResp.user_code $verificationUri = if ($codeResp.verification_uri_complete) { $codeResp.verification_uri_complete } else { $codeResp.verification_uri } $interval = if ($codeResp.interval -and $codeResp.interval -gt 0) { $codeResp.interval } else { 5 } $expiresIn = if ($codeResp.expires_in) { $codeResp.expires_in } else { 600 } Write-Host '' Write-Host ' To authenticate, open the following URL in your browser:' -ForegroundColor Cyan Write-Host '' Write-Host " $verificationUri" -ForegroundColor Yellow Write-Host '' Write-Host " And enter this code: $userCode" -ForegroundColor Green Write-Host '' Write-Host ' Waiting for authorization...' -ForegroundColor Gray $tokenUri = "$baseUrl/api/v1/auth/device/token" $deadline = [DateTime]::UtcNow.AddSeconds($expiresIn) $consecutiveErrors = 0 while ([DateTime]::UtcNow -lt $deadline) { Start-Sleep -Seconds $interval $tokenBody = @{ client_id = 'onepam-cli' device_code = $deviceCode grant_type = 'urn:ietf:params:oauth:grant-type:device_code' } try { $tokenResp = Invoke-RestMethod -Uri $tokenUri -Method Post -Body $tokenBody ` -ContentType 'application/x-www-form-urlencoded' ` -UserAgent "onepam-powershell/$script:ModuleVersion" ` -ErrorAction Stop $consecutiveErrors = 0 } catch { $consecutiveErrors++ if ($consecutiveErrors -ge 3) { Write-Host " Warning: repeated connection errors ($consecutiveErrors): $_" -ForegroundColor Yellow } if ($consecutiveErrors -ge 10) { throw "Authorization polling failed after $consecutiveErrors consecutive errors: $_" } continue } if ($tokenResp.error) { switch ($tokenResp.error) { 'authorization_pending' { continue } 'slow_down' { $interval = $interval + 5 continue } 'expired_token' { throw 'Device code expired. Please run Connect-OnePAM again.' } default { throw "Authentication error: $($tokenResp.error)" } } } if ($tokenResp.access_token) { $tokenCache = [PSCustomObject]@{ access_token = $tokenResp.access_token refresh_token = $tokenResp.refresh_token expires_at = [DateTime]::UtcNow.AddSeconds($tokenResp.expires_in).ToString('o') user_email = $tokenResp.user_email org_uuid = $tokenResp.org_uuid } Save-OpToken $tokenCache Write-Host '' Write-Host " Authenticated as $($tokenResp.user_email)" -ForegroundColor Green Write-Host " Organization: $($tokenResp.org_uuid)" -ForegroundColor Gray Write-Host '' return } } throw 'Device code flow timed out. Please try again.' } |