powershellapiresthttp-headerssecurestring

PowerShell include SecureString in request header


Using PowerShell to retrieve an auth token for a set of APIs. The endpoint requires several headers, including a "secret", "id1", and "id2" among others.

How to include the secret in the header as SecureString, or other such format that similarly protects it?

Code works when $secret is a plain old String type.

function Invoke-RestCall
{
    param
    (
        [Guid]$id1,
        [string]$id2
        [Security.SecureString]$clientSecret,
        #... other parameters for other headers
    )

    $uri = "https://..." #uri removed for public SO posting

    $headers = @{}
    $headers.Add("X-Id1", $id1)
    $headers.Add("X-Id2", $id2)
    $headers.Add("X-Secret", $clientSecret) # <-- how to convert from secure format?
    # other headers go here
    $response = Invoke-RestMethod -Uri $uri -Method GET -Headers $headers
    $response | ConvertTo-Json
}

A simple attempt at converting the secret to an encrypted string, such as

$headers.Add("X-Secret", (ConvertFrom-SecureString -Key $secret))

causes the call to return 400 Bad Request.

SecureString seems to be the most intuitive type to use. It's been a while since I worked with PowerShell so I'm not familiar with all the options. PSCredential and NetworkCredential seems like overkill but I'm still learning how to properly use them.


Solution

  • Here is how you can structure your function so that the secret is passed as plain text, you can either use [System.Net.NetworkCredential]::new('', $clientSecret).Password if you're on Windows PowerShell 5.1 or if you have PowerShell 7+ you can also use $clientSecret | ConvertFrom-SecureString -AsPlainText.

    Ideally, if your API supports more robust authentication methods you shouldn't use this one, but that's up to the API.

    function Invoke-RestCall {
        param (
            [Guid] $id1,
            [string] $id2,
            [securestring] $clientSecret,
            [uri] $uri = "https://...",
            [Microsoft.PowerShell.Commands.WebRequestMethod] $Method = 'GET'
            #... other parameters for other headers
        )
    
        $requestParams = @{
            Method  = $Method
            Uri     = $uri
            Headers = @{
                "X-Id1"    = $id1
                "X-Id2"    = $id2
                "X-Secret" = [System.Net.NetworkCredential]::new('', $clientSecret).Password
            }
        }
    
        Invoke-RestMethod @requestParams | ConvertTo-Json
    }