Access token validation failure for AD graph API after using the token acquired from AzureRmContext in Powershell - azure

I am trying to make API calls to Microsoft graph API using Oauth2 to log in.
I tried to use AzureRm cmdlet to get the token for my account, so I can make the API calls, but the message "Access token validation failure. Invalid audience." showed up in the JSON response.
Login-AzureRmAccount
$currentAzureContext = Get-AzureRmContext
$tenantId = $currentAzureContext.Tenant.Id
$accountId = $currentAzureContext.Account.Id
$tokenCache = $currentAzureContext.TokenCache
$cachedTokens = $tokenCache.ReadItems() `
| where { $_.TenantId -eq $tenantId }
$accessToken = $cachedTokens.AccessToken
Invoke-RestMethod -Method Get `
-Uri ("https://graph.microsoft.com/v1.0/me") `
-Headers #{ "Authorization" = "Bearer " + $accessToken }
The following is the JSON response:
Invoke-RestMethod : {
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure. Invalid audience.",
"innerError": {
"request-id": "8429e520-401b-4382-adad-4f55bccbe752",
"date": "2019-11-04T16:53:27"
}
}
}

Have a look at the token in https://jwt.ms and see what is the aud claim. I think the token you get via AzureRm is an access token to the Azure Management APIs. The value for MS Graph is 'https://graph.microsoft.com'. You can use the AzureAD PS module to get Graph tokens. Also note that AAD is notthe same as MS Graph.

Related

Creating Azure Runbook using a System assigned identity to make a GRAPH Request

Currently I am authenticating the system management identity using the resources found here
Runbook Authentication Tutorial
In the tutorial I am using this workflow to connect to my System management identity
# Resources
# https://learn.microsoft.com/en-us/azure/automation/learn/automation-tutorial-runbook-textual
# https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Cpowershell
param(
[String] $resourceGroup = "ResourceGroupName", # Resource Group
[String] $subscription = "SubscriptionName", # Subscription name
[String] $SAMI = "Default tenant ID" # System Access Management Identity (Tenant ID)
)
$automationAccount = "myAutomationAccountName"
Disable-AzContextAutosave -Scope Process | out-null
try {
$AzureContext = (Connect-AzAccount -Identity).context
$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile)
$token = $profileClient.AcquireAccessToken($AzureContext.Subscription.TenantId)
if(-not ($token.AccessToken)){
throw
}
$authHeader = #{
'Content-Type'='application/json'
'Authorization'='Bearer ' + $token.AccessToken
'ExpiresOn' = $token.ExpiresOn
'X-IDENTITY-HEADER'= $env:IDENTITY_HEADER
}
# Output the generated access token
Write-Output $token.AccessToken
# I want to make a graph request getting a list of devices and then use that to set the last logged-on user as the primary user. I can't even make a request though...
$uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices"
Invoke-RestMethod -Uri $uri -Headers $authHeader -Method Get
} catch{
write-output $_.Exception.Message
}
$AzureContext = Set-AzContext -SubscriptionName $subscription -DefaultProfile $AzureContext
When I start the runbook in the Testpane it outputs the JWT. Then, when trying to make the request it throws an error
The remote server returned an error: (401) Unauthorized.
I then open PostMan and enter the URL (endpoint) where I know a valid JWT created from my user account would work, I place this generated token in the Authorization Bearer token and receive this JSON error
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure. Invalid audience.",
"innerError": {
"date": "2022-08-22T19:14:43",
"request-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx",
"client-request-id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx"
}
}
}
I go to https://jwt.io/ and get the encoded JWT, and notice that the expiration date is exactly when it was created. Is this a possible problem? If so how can I extend the expiration date within this runbook? or else, is it a role-based issue with GRAPH API rejecting the token? Please help...
I have followed MSDOC I can be able to view the Graph request in a write-output.
Make sure specific Read access Role assigned to the specific user.
Workaround
I have made a request in an Azure Runbook to catch the response of a Graph request.
Result

How to manage the Azure APIM developer portal delegation with Azure PowerShell

I want to enable the Azure APIM developer portal sign-in & sign-up delegation and to generate a "Delegation Validation Key". This is straightforward with the Azure portal:
I want to achieve the same thing but with Azure PowerShell as part of a bigger deployment pipeline.
I cannot find any documentation on how to do that.
Thanks
AFAIK, We can not achieve the above requirement using powershell , Here are the details (MICROSOFT DOCUMENTATION) for what we can configure through powershell for APIM .
Instead of that we can configure the above requirement using git , Please refer this MICRSOFT DOCUMENTATION for more details & the list of cmdlets for APIM .
An additional option is to use an HTTP call against the resource. The call can be made with the PowerShell script as well.
This can be done as follows:
Get an Azure access token - you should have a Service Principal with sufficient permissions for the resource we are going to deal with.
$tokenUri = "https://login.microsoftonline.com/${tenantId}/oauth2/token"
$form = #{
grant_type = 'client_credentials'
resource = 'https://management.core.windows.net/'
client_id = $spClientId
client_secret = $spClientSecret
}
$response = Invoke-RestMethod -Uri $tokenUri -Method Post -Body $form
$azureToken = $response.access_token
Send an HTTP request against the APIM service
$url = "https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${apiManagementRg}/providers/Microsoft.ApiManagement/service/${apiManagementName}/portalsettings/delegation?api-version=2020-12-01"
$headers = #{ 'Authorization' = "Bearer ${azureToken}" }
$body = #"
{
"properties": {
"url": "$delegationUrl",
"validationKey": "$validationKey",
"subscriptions": {
"enabled": false
},
"userRegistration": {
"enabled": true
}
}
}
"#
$delegationResponse = Invoke-RestMethod -Method 'Put' -Body $body -Uri $url -Headers $headers

Defender 365 REST API (you don't have any of the required app permissions (Incident.ReadWrite.All, Incident.Read.All) to access resource)

I am trying to download list of incidents from Defender 365 (MDATP).
I have a script to get a Bearer Token:
. 'Functions\Credentials.ps1'
Function GET_BEARER_TOKEN_FOR_MDATP_AUTHENTICATION {
$Body = [Ordered] #{
resource = "$ResourceApplicationIdUri"
client_id = "$ApplicationId"
client_secret = "$ApplicationSecret"
grant_type = 'client_credentials'
}
try {
$Response = Invoke-RestMethod -Method Post -Uri $OAuthenticationURI -Body $body -ErrorAction Stop
}
catch {
Write-Output("unable to get the bearer token")
Exit
}
$BearerToken = $Response.access_token
return $BearerToken
}
$xx = GET_BEARER_TOKEN_FOR_MDATP_AUTHENTICATION
$xx | Out-File '.\Bearer_Token.txt'
That script worked fine. Today, I have been granted permission to display incidents.
When I try to do that, I get the error message:
{
"error": {
"code": "Forbidden",
"message": "The application does not have any of the required application permissions (Incident.ReadWrite.All, Incident.Read.All) to access the resource.",
}
}
When I check in the token tester website: https://jwt.ms/
I cannot see those incident.Read.All Roles but only:
"roles": [
"Alert.ReadWrite.All",
"AdvancedQuery.Read.All"
]
Roles have been given by this instruction manual:
https://learn.microsoft.com/en-us/microsoft-365/security/defender/api-create-app-web?view=o365-worldwide
Many Thanks,
Aster
so I have found the issue:
$ResourceApplicationIdUri = 'https://api.securitycenter.microsoft.com' (Alerts are allowed)
$ResourceApplicationIdUri = 'https://api.security.microsoft.com' (Incidents are allowed)
Regards,
Aster

How to authenticate for https://management.azure.com api?

I want to retrieve data on my DNS zones through a API call:
$api = "?api-version=2018-05-01"
$pat = "Bearer $env:System_AccessToken"
Write-Host "### PAT ###"
Write-Host $pat
$DNSInformation = "https://management.azure.com/subscriptions/$subscriptionId/resourceGroups/$resourceGroupName/providers/Microsoft.Network/dnsZones/$zoneName/$recordType/$relativeRecordSetName$api"
Write-Host "###"
Write-Host $DNSInformation
Write-Host "###"
$x = Invoke-RestMethod -Uri $DNSInformation -Headers #{Authorization = $pat } -Method Get
When I run this script I get:
The remote server returned an error: (401) Unauthorized.
When I navigate to the URL I get:
error: {
code: "AuthenticationFailed",
message: "Authentication failed. The Authorization header is missing."
}
I think the issue is that I can't use the $env:System_AccessToken token to get on the management api. But I can't find information what kind of authentication is needed.
As the error mentions, the authorization header is incorrect.
$URI = "https://management.azure.com/providers/microsoft.resources/checkresourcename?api-version=2014-01-01"
Invoke-RestMethod -Uri $URI -Method GET -Headers $authHeader
You can use a couple of approaches to create your header:
As you mentioned - Azure Powershell to check resource names
By creating Bearer token : Powershell Script to delete unused resources in Azure

Azure AD Access Token Without ADAL

I am trying to edit a user's AD profile on the server side which requires an access token. I can do this with the native app example which uses only a client id and secret. The docs mention that this is possible with only http requests (see Get Access Token), but I can't find any example or way to do this.
You can use OAuth2 to request an access token. Here is an example on how you use OAuth2 with Azure AD. It's written in PowerShell Script.
$tenantID = "<the Tenant ID of your Azure AD>"
$loginEndpoint = "https://login.windows.net/"
$graphResourceURI = "https://graph.windows.net/"
$clientId = "<the client id of your AD application>"
$key = "<the client secret of your AD application>"
# the URL for requesting access token.
$tokenURL = $loginEndpoint+$tenantID+"/oauth2/token"
# the token request body.
$body = "grant_type=client_credentials&client_id="+$clientId `
+"&client_secret="+[system.uri]::EscapeDataString($key) `
+"&resource="+[system.uri]::EscapeDataString($graphResourceURI)
# the token request headers.
$headers = #{"Content-Type"="application/x-www-form-urlencoded"}
$authenticationResult = Invoke-RestMethod -Method POST `
-Uri $tokenURL -Headers $headers -Body $body
$authenticationResult.access_token
The AD application you use here must be "Web application and/or web API", because a Native AD application does not have client secret.
I got this to work using Jack's answer but with a couple of changes. Here is the complete working example:
$tenantID = "<the name of your tenant of your Azure AD>"
$loginEndpoint = "https://login.windows.net/"
$graphResourceURI = "https://graph.windows.net/"
$clientId = "<the client id of your AD application>"
$key = "<the client secret of your AD application>"
# the URL for requesting access token.
$tokenURL = $loginEndpoint+$tenantID+"/oauth2/token"
# the token request body.
$body = "grant_type=client_credentials&client_id="+$clientId `
+"&client_secret="+[system.uri]::EscapeDataString($key) `
+"&resource="+[system.uri]::EscapeDataString($graphResourceURI)
# the token request headers.
$headers = #{"Content-Type"="application/x-www-form-urlencoded"}
$authenticationResult = Invoke-RestMethod -Method POST `
-Uri $tokenURL -Headers $headers -Body $body
$authenticationResult.access_token

Resources