I have an Azure CLI task in a release pipeline that I would like to make an API call from back to the same project. The task is executing under a Service Principal, and it makes available the servicePrincipalId
, servicePrincipalKey
and tenantId
to the script.
How can I use the Service Principal's credentials to authenticate a Invoke-RestMethod
API request?
You can use the Service Principal's credentials to authenticate a Invoke-RestMethod API request with the servicePrincipalId
, servicePrincipalKey
and tenantId
.
First, you can check the document to learn about Use service principals & managed identities in Azure DevOps. To use the Service Principal's credentials, we should add the service principal to Azure DevOps organization.
Here are the steps:
Here are the sample YAMLs:
az account get-access-token
command to get the token. This is also mentioned in this Q&A Can I use a service principal or managed identity with Azure CLI?.- task: AzureCLI@2
inputs:
azureSubscription: 'Test'
scriptType: 'ps'
scriptLocation: 'inlineScript'
inlineScript: |
Write-Host "Obtain access token for Service Connection identity..."
$accessToken = az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query "accessToken" --output tsv
Write-Host "Use access token with Azure DevOps REST API to list projects in the organization..."
$uri = "https://dev.azure.com/orgname/_apis/projects?api-version=7.1-preview.1"
$headers = @{
Accept = "application/json"
Authorization = "Bearer $accessToken"
}
$response =Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
$response | ConvertTo-Json
servicePrincipalId
, servicePrincipalKey
and tenantId
to get the token.- task: AzureCLI@2
displayName: Use servicePrincipalId, servicePrincipalKey and tenantId
inputs:
azureSubscription: 'Test'
scriptType: 'ps'
addSpnToEnvironment: true
scriptLocation: 'inlineScript'
inlineScript: |
$tenantId = $env:tenantId
$clientId = $env:servicePrincipalId
$clientSecret = $env:servicePrincipalKey
$resource = "499b84ac-1321-427f-aa17-267ca6975798" #(the Azure DevOps resource's UUID is 499b84ac-1321-427f-aa17-267ca6975798)
$body = @{
grant_type = "client_credentials"
client_id = $clientId
client_secret = $clientSecret
resource = $resource
}
# Get the token
$tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/token" -Body $body
$token = $tokenResponse.access_token
Write-Host "Use servicePrincipalId, servicePrincipalKey and tenantId with Azure DevOps REST API to list project in the organization..."
$uri = "https://dev.azure.com/orgname/_apis/projects?api-version=7.1"
$headers = @{
Accept = "application/json"
Authorization = "Bearer $token"
}
$response =Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
$response | ConvertTo-Json
By the way, there is another easy way make an API call from back to the same project is to use the System.AccessToken. This way, we don't need to add the service principal to Azure DevOps organization.
- task: AzureCLI@2
displayName: Use System.AccessToken
inputs:
azureSubscription: 'Test'
scriptType: 'ps'
scriptLocation: 'inlineScript'
inlineScript: |
Write-Host "Use System.AccessToken with Azure DevOps REST API to list project in the organization..."
$uri = "https://dev.azure.com/orgname/_apis/projects?api-version=7.1"
$headers = @{
Accept = "application/json"
Authorization = "Bearer $(System.AccessToken)"
}
$response =Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
$response | ConvertTo-Json