Wilfried Woivré

Cloud Solution Architect - MVP Microsoft Azure

Generate an Azure AD Token using the REST API

Categories : Azure Azure   Powershell Powershell   Azure Active Directory Azure Active Directory


Recently, I had to access to a storage account using an application account, so I set up a SPN which has an RBAC right on my storage account, as I show in this blog post: https://woivre.com/blog/2020/01/login-to-your-storage-accounts-using-azure-active-directory

Now I need to generate my access token, thing that may be easy using ADAL libraries, however for my usecase I had the following constraints :

  • Application account and a certificate authentication
  • No additional libraries (Ciao ADAL)
  • Powershell

First, we need to generate a JWT Token. As a reminder a JWT Token has the following syntax : base64(header).base64(payload).base64(signature)

Let’s start by building our header. To achieve this, we need to get the hash of our certificate :

$cert = Get-Item Cert:\CurrentUser\My\$ThumbprintValue

$hash = $cert.GetCertHash()
$hashValue = [System.Convert]::ToBase64String($hash)  -replace '\+','-' -replace '/','_' -replace '='

Now, it’s possible to build our header and payload as following :

[hashtable]$header = @{alg = 'RS256'; typ= "JWT"; x5t = $thumprintValue}
[hashtable]$payload = @{aud = "https://login.microsoftonline.com/$TenantUrl/oauth2/token"; iss = $applicationId; sub=$applicationId; jti = "22b3bb26-e046-42df-9c96-65dbd72c1c81"; exp = $exp; nbf= 1536160449}

Now that we have all the information, we need to generate our signature and construct the token :

$headerjson = $header | ConvertTo-Json -Compress
$payloadjson = $payload | ConvertTo-Json -Compress

$headerjsonbase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($headerjson)) -replace '\+','-' -replace '/','_' -replace '='
$payloadjsonbase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($payloadjson)) -replace '\+','-' -replace '/','_' -replace '='

$jwt = $headerjsonbase64 + "." + $payloadjsonbase64
$toSign = [System.Text.Encoding]::UTF8.GetBytes($jwt)

$Signature = [Convert]::ToBase64String($rsa.SignData($toSign,[Security.Cryptography.HashAlgorithmName]::SHA256,[Security.Cryptography.RSASignaturePadding]::Pkcs1)) -replace '\+','-' -replace '/','_' -replace '='

$token = "$headerjsonbase64.$payloadjsonbase64.$Signature"

You can check that the creation the JWT Token on some sites such as : https://jwt.io/

Here is it. We have the JWT Token which allows us to get the Access Token :


$url = "https://login.microsoftonline.com/$TenantUrl/oauth2/token"
$body = "resource=https%3A%2F%2F$storageAccountName.blob.core.windows.net%2F&client_id=$applicationId&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=$token&grant_type=client_credentials"
$responseToken = Invoke-WebRequest -Method POST -ContentType "application/x-www-form-urlencoded"  -Headers @{"accept"="application/json"} -Body $body $url -Verbose

$accessToken = ($responseToken.Content | ConvertFrom-Json).access_token

After generating the token, it is possible to add it to the headers so we can call the storage account’s REST API.

$headerSMA =  @{"Authorization" = "Bearer " + $accessToken; "x-ms-version" = "2017-11-09"}
Invoke-WebRequest -Headers $headerSMA -Method GET "https://$storageAccountName.blob.core.windows.net/$containerName/$blobName"  -OutFile $outFile

That’s how we request the Azure API without using the ADAL. even if it is more easier using ADAL and you have less things to know.

Comments

Post comment
Loading...