Authentication.psm1

<#
.SYNOPSIS
    This function retrieves the TechData API headers using admin account credentials or a MSPComplete Endpoint.
.DESCRIPTION
    This function retrieves the TechData API request headers using admin account credentials or a MSPComplete Endpoint.
    It returns the request headers if successful, null otherwise.
.PARAMETER url
    The TechData authentication URL.
.PARAMETER clientID
    The TechData client ID.
.PARAMETER clientSecret
    The TechData client secret.
.PARAMETER grantType
    The TechData grant type.
.PARAMETER soin
    The TechData StreamOne Identification Number (SOIN)
.PARAMETER endpoint
    The MSPComplete Endpoint containing the TechData authentication URL as its "Url" property, the
    TechData client ID, client secret and grant type, and SOIN as
    "ClientID", "ClientSecret", "GrantType" and "SOIN" extended properties
.EXAMPLE
    Get-TechDataAccessToken -Endpoint $Endpoint
.EXAMPLE
    $Endpoint | Get-TechDataAccessToken
.EXAMPLE
    Get-TechDataAccessToken -Url $url -ClientID $clientID -ClientSecret $clientSecret -GrantType $grantType -Soin $soin
#>

function Get-TechDataApiHeaders {
    param (
        # The TechData authentication URL.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$url,

        # The TechData client ID.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$clientID,

        # The TechData client secret.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$clientSecret,

        # The TechData grant type.
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$grantType,

        # The TechData StreamOne Identification Number (SOIN)
        [Parameter(Mandatory=$true, ParameterSetName="credential")]
        [String]$soin,

        # The MSPComplete Endpoint containing the TechData authentication URL as its "Url" property, the
        # TechData client ID, client secret and grant type, and SOIN as
        # "ClientID", "ClientSecret", "GrantType" and "SOIN" extended properties
        [Parameter(Mandatory=$true, ParameterSetName="endpoint", ValueFromPipeline=$true)]
        $endpoint
    )

    try {
        # If given endpoint, retrieve values for authentication
        if ($PSCmdlet.ParameterSetName -eq "endpoint") {
            # Retrieve authentication URL
            if ([String]::IsNullOrWhiteSpace($endpoint.Configuration.Url)) {
                Write-Error "Endpoint has null/empty 'Url' property."
                return $null
            }
            $url = $endpoint.Configuration.Url

            # Retrieve client ID
            if ([String]::IsNullOrWhiteSpace($endpoint.ExtendedProperties.ClientID)) {
                Write-Error "Endpoint has null/empty 'ClientID' extended property."
                return $null
            }
            $clientID = $endpoint.ExtendedProperties.ClientID

            # Retrieve client secret
            if ([String]::IsNullOrWhiteSpace($endpoint.ExtendedProperties.ClientSecret)) {
                Write-Error "Endpoint has null/empty 'ClientSecret' extended property."
                return $null
            }
            $clientSecret = $endpoint.ExtendedProperties.ClientSecret

            # Retrieve grant type
            if ([String]::IsNullOrWhiteSpace($endpoint.ExtendedProperties.GrantType)) {
                Write-Error "Endpoint has null/empty 'GrantType' extended property."
                return $null
            }
            $grantType = $endpoint.ExtendedProperties.GrantType

            # Retrieve SOIN
            if ([String]::IsNullOrWhiteSpace($endpoint.ExtendedProperties.SOIN)) {
                Write-Error "Endpoint has null/empty 'SOIN' extended property."
                return $null
            }
            $soin = $endpoint.ExtendedProperties.SOIN
        }

        # Construct call to authentication server
        $headers = @{
            "Content-Type" = "application/x-www-form-urlencoded"
        }
        $body = @{
            client_id = $clientID
            client_secret = $clientSecret
            grant_type = $grantType
        }

        # Invoke request to get the token
        try {
            $timestamp = [Int]((Get-Date).TimeOfDay.TotalMilliseconds)
            $response = Invoke-RestMethod -Uri $url -Headers $headers -Body $body -Method "POST"
        }
        catch {
            Write-Error "Error while invoking POST request. `r`n$($_.Exception.Message)"
            return $null
        }

        # Construct the headers for API calls
        $signatureBytes = [System.Text.Encoding]::UTF8.GetBytes("$($response.access_token):$($soin):$($timestamp)")
        $encodedSignature = [Convert]::ToBase64String($signatureBytes)
        $apiHeaders = @{
            "Content-Type" = "application/json"
            "Authorization" = "Bearer $($response.access_token)"
            "SOIN" = $soin
            "TimeStamp" = $timestamp
            "Signature" = $encodedSignature
            "Accept" = "application/json"
        }

        # Return the headers
        return $apiHeaders
    }
    catch {
        Write-Error "Exception occurred on line $($_.InvocationInfo.ScriptLineNumber): `r`n$($_.Exception.Message)"
        return $null
    }
}