Private/Authentication/Acronis/Get-AcronisAccessToken.ps1

function Get-AcronisAccessToken {
    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$Force
    )

    begin {
        try {
            if (!$script:AcronisCredentials -or $script:AcronisCredentials.Account -ne $Account) {
                $script:AcronisCredentials = Get-AcronisCredentials
            }

            $datacenterUri = 'https://dk01-cloud.acronis.com'
            $tokenEndpoint = "$datacenterUri/bc/idp/token"
            $base64EncodedCredentials = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($script:AcronisCredentials.ClientId):$($script:AcronisCredentials.ClientSecret)"))
        }
        catch {
            Write-ModuleLog -Message "Failed to get Acronis credentials" -Level Error -Component 'AcronisAccessToken' -ErrorRecord $_
            throw
        }
    }

    process {
        try {
            $cacheKey = "AcronisAccessToken"
            $now = Get-Date

            # Check cache for valid token
            if (!$Force -and $script:TokenCache.ContainsKey($cacheKey)) {
                $cachedToken = $script:TokenCache[$cacheKey]
                
                # Token is still valid
                if ($cachedToken.ExpirationDateTime -gt $now) {
                    Write-ModuleLog -Message "Using cached token for $cacheKey" -Level Verbose -Component 'AcronisAccessToken'
                    return $cachedToken
                }
            }

            Write-ModuleLog -Message "Getting new token for $cacheKey" -Level Verbose -Component 'AcronisAccessToken'

            # Prepare token request
            try {
                $headers = @{
                    'Authorization' = "Basic $base64EncodedCredentials"
                    'Content-Type' = 'application/x-www-form-urlencoded'
                }
                $body = @{
                    'grant_type' = 'client_credentials'
                }

                $response = Invoke-RestMethod -Uri $tokenEndpoint `
                    -Method POST `
                    -Headers $headers `
                    -Body $body `

                # Create token object with formatted Authorization header value
                $token = [PSCustomObject]@{
                    AccessToken         = $response.access_token
                    AuthorizationHeader = "Bearer $($response.access_token)"
                    TokenType          = $response.token_type
                    ExpirationDateTime = (Get-Date).AddSeconds($response.expires_in)
                    Scope             = $response.scope
                }
            }
            catch {
                $detailedError = switch -Regex ($_.Exception.Message) {
                    'invalid_client' { 'Invalid client credentials' }
                    'invalid_scope' { 'Invalid scope requested' }
                    'invalid_request' { 'Malformed request' }
                    default { $_.Exception.Message }
                }

                Write-ModuleLog -Message "Failed to acquire Acronis token: $detailedError" -Level Error -Component 'AcronisAccessToken' -ErrorRecord $_
                throw
            }
            
            # Manage cache
            try {
                if ($script:TokenCache.Count -ge $script:TokenCacheConfig.MaxSize) {
                    $oldestTokens = $script:TokenCache.GetEnumerator() | 
                    Sort-Object { $_.Value.ExpirationDateTime } |
                    Select-Object -First ($script:TokenCache.Count - $script:TokenCacheConfig.MaxSize + 1)
                    
                    foreach ($oldToken in $oldestTokens) {
                        $script:TokenCache.Remove($oldToken.Key)
                    }
                }

                $script:TokenCache[$cacheKey] = $token
                Save-TokenCache
            }
            catch {
                Write-ModuleLog -Message "Failed to manage token cache" -Level Error -Component 'AcronisAccessToken' -ErrorRecord $_
            }
            
            return $token
        }
        catch [AcronisTokenOperationException] {
            throw
        }
        catch {
            Write-ModuleLog -Message "An unexpected error occurred during token operation" -Level Error -Component 'AcronisAccessToken' -ErrorRecord $_
            throw
        }
    }
}