One Tool, All APIs: API Authentication With PowerShell

This is the second post in the One Tool, All APIs: PowerShell series. Previous post:

Today we are going to explore API Authentication with PowerShell, specifically with Invoke-WebRequest and Invoke-RestMethod.

API Authentication Options

There are quite few approaches/mechanism of performing API authentication. The main suspects are:

  • Basic Authentication – client sends an HTTP containing a username and password typically in the form of a Base64-encoded string in the header.
    • Security Factor: not very secure as credentials can be easily intercepted if not used over HTTPS or with MitM attack.
  • Token-based Auth – client sends a token, usually generated by the server, in the request header to access the API. 
    • Security Factor: API keys are less secure than other methods because they can be easily exposed if not handled properly.
  • OAuth – open standard for access delegation, which allows the client to access resources on behalf of the resource owner, without sharing the owner’s credentials. 
    • Security Factor: Pretty secure method but heavily depends on proper OAuth 2.0 flows configurations to ensure the security of APIs.

Our cmdlets support majority of the authentication options:

Let’s see how each of the authentication method can be used via our Invoke-WebRequest and Invoke-RestMethod cmdlets.

Basic Authentication

For our basic auth testing we will be using simple HTTP Request & Response Service – httpbin.org and specifically its Basic Authentication endpoint: https:///basic-auth/{user}/{passwd}

It prompts for the credentials and expects to receive the specified in url ones.

Invoke-WebRequest

First, let’s without any credentials.

$r=Invoke-WebRequest -uri https://httpbin.org/basic-auth/user/pass

Well, that is expected. We need to pass the credentials for authentication.

$Creds=Get-Credential
$r=invoke-WebRequest -uri https://httpbin.org/basic-auth/user/pass -Credential $Creds
$r.content

This looks much better than the unauthenticated request. We do receive the successful response from the API. In addition, to response json payload we have rich BasicHtmlWebResponseObject object with multiple properties and methods. For more details please refer here.

Invoke-RestMethod

With RestMethod we can use identical approach but change the name of the cmdlet (obviously). So to make it more fun and interesting we will craft the request and response will be parsed for us.

For starters, no credentials:

$r=Invoke-RestMethod -uri https://httpbin.org/basic-auth/user/pass

And the expected HTTP 401 Error code.

Now, let’s add the authentication headers. For that, we will need to use few more lines than just Get-Credential:

  1. Convert username and password to Base64 with a “:” (colon) as separator
  2. Craft “Basic Auth” header, it sounds complicated but in reality it is just “Authorization” key name and “Basic” plus Base64 string as the key value.

$user="user"
$pass="pass"
$base64Auth=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${user}:${pass}"))
$headers = @{"Authorization" = "Basic $base64Auth"}
$r=Invoke-RestMethod -Uri https://httpbin.org/basic-auth/user/pass -Headers $headers -Method Get
$r

Token-based Authentication

We are going to use the same service for our examples (httpbin.org), just different API endpoint: https://httpbin.org/bearer

The overall approach for both cmdlets is identical:

  1. Craft the “Authorization” header using “Authorization” key name and “Bearer” followed by the API access token as the key value

$token="ba272862-9d46-4f45-beb9-f73c5795a1ca"
$headers=@{"Authorization" = "Bearer $token"}

After we crafted the header, we simply send request to the API endpoint.

Invoke-WebRequest

$response=Invoke-WebRequest -Uri "https://httpbin.org/bearer" -Headers $headers -Method Get

Invoke-RestMethod

$response=Invoke-RestMethod -Uri "https://httpbin.org/bearer" -Headers $headers -Method Get

OAuth

Typical OAuth flow can be summarized in the following steps:

In our examples we will be using Azure AD and Microsoft Graph API endpoint. Microsoft Graph API is API service in our case and Azure AD is our Authorization Server.

For the sake of simplicity, I will reach out to Authorization Server (Azure AD) to get Access Token.

Please note: I’ve already registered Application in Azure AD and obtained AppID and AppSecret values.

After that using the obtained access code, I will reach one of the Microsoft Graph API endpoints.

Let’s prepare the Body and Urls that we will use with our cmdlets.

$Body=@"
  grant_type="client_credentials"
   &client_id=$ClientId
   &client_secret=$ClientSecret
   &resource:https://graph.microsoft.com/
   &scope="https://graph.microsoft.com/.default"
"@
$tokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

Invoke-WebRequest

$token=Invoke-WebRequest -Uri $tokenEndpoint -Method Post -Body $Body -ContentType "application/x-www-form-urlencoded" | Select-Object -ExpandProperty Content | ConvertFrom-Json | Select-Object -ExpandProperty access_token

Now, when we obtained access_token we will get data from our API using the token-based authentication.

$headers=@{"Authorization" = "Bearer $token"}
$response=Invoke-WebRequest -Uri "https://graph.microsoft.com/v1.0/users" -Headers $headers -Method Get
$response.Content | ConvertFrom-Json | Select-Object -ExpandProperty Value

Invoke-RestMethod

Here we will use the same code just different cmdlet and less actions for transforming the response to the desired output.

$token=Invoke-RestMethod -Uri $tokenEndpoint -Method Post -Body $Body -ContentType "application/x-www-form-urlencoded" | Select-Object -ExpandProperty access_token
$headers=@{"Authorization" = "Bearer $token"}
$response=Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users" -Headers $headers -Method Get

As you can see, with flexibility and modularity that is baked in PowerShell out of the box and a little bit of knowledge (and understanding) of the API Authentication methods and flows we can use both cmdlets to get data from API services. The main differences are the in the preparation of the headers and body for the request and steps needed to handle the response. For Invoke-WebRequest main use case is to interact with Website, meaning that response object will contain more data and it will take more effort to get the needed values. On the other hand, Invoke-RestMethod is designed to interact with Rest API endpoints and receive json data in the response.

Next: API Parameters with PowerShell

Icons created by Freepik – Flaticon.

Thanks a lot for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.