Public/Connect-MyWebApi.ps1
|
function Connect-MyWebApi { <# .SYNOPSIS Creates an isolated WebAPI v2 session and makes it the optional default connection. .DESCRIPTION Returns a connection object. Pass that object to generated cmdlets with -Connection when more than one target is used; omitting -Connection retains the single-session convenience API. OAuth discovery is same-origin by default and all endpoints require HTTPS, except an explicit loopback-only HTTP opt-in for tests. #> [CmdletBinding()] param( [Parameter()][ValidateSet('Staging','Production')][string] $Environment, [Parameter()][string] $BaseUrl, [Parameter()][string] $Authority, [Parameter()][string] $ClientId, [Parameter()][SecureString] $ClientSecret, [Parameter()][string] $AccessToken, [Parameter()][string] $Scope = 'webapi', [Parameter()][string] $DefaultTradePlatform, [Parameter()][string] $TrustedTokenEndpoint, [Parameter()][switch] $AllowInsecureLoopback, [Parameter()][ValidateRange(1, 600)][int] $HttpTimeoutSeconds = 30, [Parameter()][ValidateRange(1, 3600)][int] $RealtimeTimeoutSeconds = 30, [Parameter()][ValidateRange(0, 3)][int] $MaxGetRetries = 2 ) if ($Environment) { $environmentConfig = Resolve-MyWebApiEnvironment -Environment $Environment $resolvedBase = $environmentConfig.BaseUrl $resolvedAuthority = $environmentConfig.Authority } else { if (-not $BaseUrl) { throw 'Provide -Environment, or -BaseUrl (and -Authority for client-credentials).' } $resolvedBase = $BaseUrl $resolvedAuthority = $Authority } if (-not $AccessToken -and -not $ClientId) { throw 'Provide either -AccessToken, or -ClientId and -ClientSecret for client-credentials.' } if (-not $AccessToken -and -not $resolvedAuthority) { throw 'Authority is required for client-credentials: pass -Environment, or -Authority with -BaseUrl.' } if (-not $AccessToken -and -not $ClientSecret) { throw 'ClientSecret is required for client-credentials.' } # Validate before storing any mutable session state. Authority and API URLs are # deliberately separate so a token endpoint can never silently redirect credentials. $candidate = [pscustomobject]@{ BaseUrl = $resolvedBase.TrimEnd('/') Authority = if ($resolvedAuthority) { $resolvedAuthority.TrimEnd('/') } else { $null } ClientId = $ClientId ClientSecret = $ClientSecret Scope = $Scope DefaultTradePlatform = $DefaultTradePlatform AccessToken = $AccessToken ExpiresAt = if ($AccessToken) { [DateTimeOffset]::UtcNow.AddHours(1) } else { $null } TrustedTokenEndpoint = $TrustedTokenEndpoint AllowInsecureLoopback = [bool]$AllowInsecureLoopback HttpTimeoutSeconds = $HttpTimeoutSeconds RealtimeTimeoutSeconds = $RealtimeTimeoutSeconds MaxGetRetries = $MaxGetRetries CancellationSource = [System.Threading.CancellationTokenSource]::new() RefreshGate = [System.Threading.SemaphoreSlim]::new(1, 1) Disposed = $false } $null = Assert-MyWebApiEndpoint -Value $candidate.BaseUrl -Name 'BaseUrl' -Context $candidate if ($candidate.Authority) { $null = Assert-MyWebApiEndpoint -Value $candidate.Authority -Name 'Authority' -Context $candidate } if ($TrustedTokenEndpoint) { $null = Assert-MyWebApiEndpoint -Value $TrustedTokenEndpoint -Name 'TrustedTokenEndpoint' -Context $candidate } # Keep the old one-session convenience while returning an explicit immutable target # reference for callers that need independent sessions. $script:MyWebApiContext = $candidate if (-not $AccessToken) { [void](Get-MyWebApiToken -Connection $candidate) } return $candidate } |