How to get Azure REST APIs access tokens using PowerShell

Dmitri Gaikovoi
ObjectSharp (a Centrilogic Company)
3 min readJun 24, 2020

Sometimes, I have to step out of the comfort of the Azure PowerShell module and call Azure REST APIs directly. Usually, it is required when there is no cmdlet wrapper for some API, or the Az module does not support some underlying API functionality.

As you already know, such calls are regular HTTP requests and can be executed by using cmdlets Invoke-WebRequest or Invoke-RestMethod. The essential part of these HTTP requests is authentication. For this purpose, the HTTP request must contain “Authorization” header that contains the access token for the API.

Note. Latest updates (Fall 2020) changed Az module behaviour. You can find summary of the related changes and new token acquisition technique here.

Little bit of theory

It is relatively easy to get the token when your code has complete control over the credentials — for example, in an interactive PowerShell session where user can provide them, or in a script that has the values of the client id and client secret for the service principal. However, often, the scripts have to be executed in an automated, non-interactive environment like CI/CD pipelines where the underlying CI/CD product (e.g. Azure DevOps) manages the access credentials and prepares the Azure Context for script execution (by implicit Connect-AzAccount cmdlet execution).

In such scenarios, it is possible to utilize the Azure PowerShell module’s ability to transparently get the access token when its cmdlets access control/data planes of the different services. For example, Get-AzKeyVault is a control plane call against the https://management.azure.com endpoint, while Get-AzKeyVaultSecret is a data plane call against the https://{some-vault}.vault.azure.net endpoint. The module uses MSAL to acquire tokens from Azure AD, cache, and renew them. A one-liner will return the list of the tokens in the current Azure PowerShell session:

(Get-AzContext).TokenCache.ReadItems()

Practice

Now, let see how we can use Azure PowerShell’s ability for our purpose — to call one of the Azure APIs.

Let say, we need to perform direct API calls against our Key Vault. To ensure that the token cache has an access token for the desired API (Key Vault), we perform a simple secret KV read using a cmdlet from Az.KeyVault module:

Get-AzKeyVaultSecret -VaultName $kvName -Name $secretName

Now, the token cache has the access token for the data plane of our Key Vault (assuming the current context identity has read access to this KV secrets and Get-AzKeyVaultSecret succeeded; the actual secrets doesn’t have to exist).

We can get this token from cache

$tokenCache = (Get-AzContext).TokenCache.ReadItems()
$cacheItem = $tokenCache | Where-Object {$_.Resource -eq 'https://vault.azure.net'}
$kvAccessToken = $cacheItem.AccessToken

and use it to call the desired API

$token = ConvertTo-SecureString -String $kvAccessToken -AsPlainText -Force
...
Invoke-RestMethod -Method Post -Uri $URI `
-ContentType "application/json" `
-Authentication Bearer -Token $token -Body $body

Side Note: In an interactive session, where the user potentially is a member of multiple Azure AD tenants or the Azure PowerShell context contains multiple session for different users, additional filtering of the token cache based on TenantId and DisplayableId (user logon name) will be required.

In my next post, I will show how I used this access token acquisition technique to solve a real life “non-standard” task.

Originally published at https://blog.gaikovoi.dev.

--

--