Unable to retrieve token from Azure API - azure

I am trying to get a token to be able to retrieve Groups information in Azure AD
This is my powershell script against the API:
Invoke-RestMethod -Method POST -Uri 'https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token?api-version=1.6'
-Header #{'Content-type' = 'application/x-www-form-urlencoded'}
-Body '{grant_type=client_credentials&client_id=<clientID>&scope=https://graph.microsoft.com/.default&client_secret=<clientSecret> }'
I keep getting this error: {"error":"invalid_request","error_description":"AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID:

Your body ia malformed, just do:
$body = #{
Grant_Type = 'client_credentials'
Scope = 'https://graph.microsoft.com/.default'
Client_Id = $ClientID
Client_Secret = $Secret
}
$con = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token" -Method 'Post' -Body $body
$token = $con.access_token

Related

Unable to create Azure B2C User Flow via powershell with b2cIdentityUserFlow

I am trying to create a user flow with PowerShell, but I receiveThe remote server returned an error: (403) Forbidden.. I was reading the documentation from Microsoft but with no success.
Connect-AzAccount -Tenant "myorg.onmicrosoft.com"
$managementAccessToken = Get-AzAccessToken -TenantId "$tenantId" -ResourceTypeName MSGraph
$DefinitionFilePath = "C:\azdeploy\flows\b2csignin.json"
$signinFlowContent = Get-Content $DefinitionFilePath
Invoke-WebRequest -Uri "https://graph.microsoft.com/beta/identity/b2cUserFlows" `
-Method "POST" `
-Headers #{
"Content-Type" = "application/json"
"Authorization" = "Bearer $($managementAccessToken.Token)";
} `
-Body $signinFlowContent
JSON Content(Default From Microsoft Docs):
{
"id": "Customer",
"userFlowType": "signUpOrSignIn",
"userFlowTypeVersion": 3
}
Connect-AzAccount is made with a user who is Global Administrator, also tried with Lifecycle Workflows Administrator permissions. I don't know what to do, trying the old API but it is deprecated. I need to create a few User Flows with а few Application Claims. How can I achieve this?
Thanks!
I tried to reproduce the same in my environment and got below results:
I created one json file with same parameters as you like below:
I have one user named Sritest having Global Administrator role like below:
When I ran the same code as you by signing in with above user, I got same error as below:
Connect-AzAccount -Tenant "myorg.onmicrosoft.com"
$managementAccessToken = Get-AzAccessToken -TenantId "$tenantId" -ResourceTypeName MSGraph
$DefinitionFilePath = "C:\test\b2csignin.json"
$signinFlowContent = Get-Content $DefinitionFilePath
Invoke-WebRequest -Uri "https://graph.microsoft.com/beta/identity/b2cUserFlows" `
-Method "POST" `
-Headers #{
"Content-Type" = "application/json"
"Authorization" = "Bearer $($managementAccessToken.Token)";
} `
-Body $signinFlowContent
Response:
You need to have IdentityUserFlow.ReadWrite.All permission to create userflow.
To resolve the error, I registered one Azure AD application and added that API permission like below:
Make sure to grant admin consent after adding API permissions in application. Now, I created one client secret and added all these details in getting access token by modifying PowerShell code.
When I ran below modified code, userflow created successfully as below:
Connect-AzureAD -TenantId "c6d99123-0cf9-4b64-bde3-xxxxxxxxx"
$graphtokenBody = #{
grant_type = "client_credentials"
scope = "https://graph.microsoft.com/.default"
client_id = "appID"
client_secret = "secret"
}
$graphToken = Invoke-RestMethod -Uri "https://login.microsoftonline.com/c6d99123-0cf9-4b64-bde3-xxxxxxxxx/oauth2/v2.0/token" -Method POST -Body $graphtokenBody
$token = $graphToken.access_token
$DefinitionFilePath = "C:\test\b2csignin.json"
$signinFlowContent = Get-Content $DefinitionFilePath
Invoke-WebRequest -Uri "https://graph.microsoft.com/beta/identity/b2cUserFlows" `
-Method "POST" `
-Headers #{
"Content-Type" = "application/json"
"Authorization" = "Bearer $($token)";
} `
-Body $signinFlowContent
Response:
To confirm that, I checked the same in Portal where B2C_1_Customer userflow is present like below:

Get-AzAccessToken keeps returning the same Token by targeting a different tenant

I have a PowerShell Azure Function that is secured with AAD. In my script I get the id token with the following command:
$assertion = $Request.Headers['x-ms-token-aad-id-token']
I use this assertion in order to get another token to use the Azure Service Management Api with the OBO Flow. Below is the code used:
$contentType = 'application/x-www-form-urlencoded'
$body = #{
grant_type = $grantType
client_id = $clientId
client_secret = $clientSecret
scope = $scope
requested_token_use = $requestedTokenUse
assertion = $assertion
}
$oboResponse = Invoke-RestMethod 'https://login.microsoftonline.com/e005f490-xxxx-4816-xxxx-b0ed7fa9xxxx/oauth2/v2.0/token' -Method 'POST' -body $body -ContentType $contentType
$accessToken = $oboResponse.access_token
Then I use this token to connect to azure with the Connect-AzAccount command. So far, everything is good well and the connection to Azure is working fine.
In my script, I try to have different tokens to connect to other tenants to which I belong. Unfortunately, it does not work as expected. Indeed the command returns the same token for different tenants. In fact, the produced token by the command "Get-AzAccessToken -TenantId $tenant.Id" is always equal to the token produced by the OBO flow.
Below is my PowerShell Azure function. I commented the part where I have a the issue.
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
$accountId = $Request.Headers['x-ms-client-principal-name']
$grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
$clientId = "xxxx"
$clientSecret = "xxxx"
$scope = "https://management.azure.com/user_impersonation"
$requestedTokenUse = "on_behalf_of"
$assertion = $Request.Headers['x-ms-token-aad-id-token']
$contentType = 'application/x-www-form-urlencoded'
$body = #{
grant_type = $grantType
client_id = $clientId
client_secret = $clientSecret
scope = $scope
requested_token_use = $requestedTokenUse
assertion = $assertion
}
$oboResponse = Invoke-RestMethod 'https://login.microsoftonline.com/e005f490-xxxx-4816-xxxx-b0ed7fa9xxxx/oauth2/v2.0/token' -Method 'POST' -body $body -ContentType $contentType
$accessToken = $oboResponse.access_token
Connect-AzAccount -AccessToken $accessToken -AccountId $accountId
$allTenants = Get-AzTenant
foreach ($tenant in $allTenants) {
# Here I get the same access token for different tenants.
# The token is always equal to the token produced by the OBO flow.
$accessToken_ = Get-AzAccessToken -TenantId $tenant.Id
....
....
}
...
...
I don't understand why the token produced by the OBO flow is always equal to the token produced by Get-AzAccessToken. I hope I have described my problem correctly, thank you for your help.
Thank you.
I think the problem is due to your Invoke-RestMethod call using a static tenant ID/GUID:
$oboResponse = Invoke-RestMethod 'https://login.microsoftonline.com/e005f490-xxxx-4816-xxxx-b0ed7fa9xxxx/oauth2/v2.0/token' -Method 'POST' -body $body -ContentType $contentType
https://login.microsoftonline.com/{**tenant**}/oauth2/v2.0/token

Azure Databricks API

Trying to use the Databricks API to work with resources programmatically. I am using this microsoft documentto authenticate with a service principal.
https://learn.microsoft.com/en-us/azure/databricks/dev-tools/api/latest/aad/service-prin-aad-token
But I'm getting the following error
"Invoke-RestMethod : {"error":"invalid_resource","error_description":"AADSTS500011: The resource principal named
https://management.core.azure.com was not found in the tenant"
This is my full script. What am I missing?
$ApiCommand = "clusters/get"
$DataBrick = "https://adb-3522222096750220.0.azuredatabricks.net"
$DataBricksResourceID = ""
$VaultName = ""
$KeyName = ""
$apiEndpointUri = "https://management.core.azure.com"
$tenantId = ""
$applicationId = ""
$secret = Get-AzKeyVaultSecret -VaultName $VaultName -Name $KeyName -AsPlainText
$RequestAccessTokenUri = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$body = "grant_type=client_credentials&client_id=$applicationId&client_secret=$secret&resource=2ff814a6-3304-4ab8-85cb-cd0e6f879c1d"
$Managementbody = "grant_type=client_credentials&client_id=$applicationId&client_secret=$secret&resource=$apiEndpointUri"
$contentType = 'application/x-www-form-urlencoded'
$AccessToken = Invoke-RestMethod -Method Post -Uri $RequestAccessTokenUri -Body $body -ContentType $contentType
Write-Output $AccessToken
$ManagementToken = Invoke-RestMethod -Method Post -Uri $RequestAccessTokenUri -Body $Managementbody -ContentType $contentType
Write-Output $ManagementToken
$apiuri = $DataBrick +"/api/2.0/$ApiCommand"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Bearer " + $AccessToken.access_token)
$headers.Add("X-Databricks-Azure-SP-Management-Token", $ManagementToken.access_token)
$headers.Add("X-Databricks-Azure-Workspace-Resource-Id", $DataBricksResourceID)
Invoke-RestMethod -Uri $apiuri -Headers $headers
The trailing / character in the management endpoint URI is really important - you need to specify it as in the documentation: https://management.core.windows.net/
You can also add this SP into the workspace itself, then you will need to get only one AAD token (see the docs).

Storage REST API Returns Remote Name Could Not be Resolve Often

I am calling the storage REST API to get container names using
Invoke-WebRequest -Method GET -Uri $storage_url -Headers $headers
This command often returns 'remote name could not be resolved error', even when the storage account exists and is reachable. Just running the command again gives correct result.
Invoke-WebRequest : The remote name could not be resolved: '<storageAccountName>.blob.core.windows.net'
At line:1 char:1
+ Invoke-WebRequest -Method GET -Uri $storage_url -Headers $headers #In ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
From the information you provided, you use the client credential flow to get the access token, then use the token to call the Storage Rest API - List Containers.
You could use the script below, it works for me.
Make sure the service principal you used has a RBAC role e.g. Contributor/Owner in your storage account -> Access Control, if not, click the Add to add it.
$ClientID = "xxxxxxx"
$ClientSecret = "xxxxxxx"
$tennantid = "xxxxxxx"
$storageaccountname = "joystoragev2"
$TokenEndpoint = {https://login.microsoftonline.com/{0}/oauth2/token} -f $tennantid
$Resource = "https://storage.azure.com/"
$Body = #{
'resource'= $Resource
'client_id' = $ClientID
'grant_type' = 'client_credentials'
'client_secret' = $ClientSecret
}
$params = #{
ContentType = 'application/x-www-form-urlencoded'
Headers = #{'accept'='application/json'}
Body = $Body
Method = 'Post'
URI = $TokenEndpoint
}
$token = Invoke-RestMethod #params
$accesstoken = $token.access_token
$url = {https://{0}.blob.core.windows.net/?comp=list} -f $storageaccountname
$header = #{
'Authorization' = 'Bearer ' + $accesstoken
'x-ms-version' = '2019-02-02'
}
$response = Invoke-WebRequest –Uri $url –Headers $header –Method GET
$response.RawContent

Microsoft Graph - Grant_Type client_credentials calendarview - Access is denied. Check credentials and try again

I am using PowerShell to get Calendar events from MS Graph.
Grant Type: client_credentials
$clientId = "xxx"
$tenantName = "xxx"
$clientSecret = "xxx"
$resource = "https://graph.microsoft.com/"
$ReqTokenBody = #{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
client_Id = $clientID
Client_Secret = $clientSecret
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
Grant Type: Password
$clientID = "xxx"
$tenantName = "xxx"
$ClientSecret = "xxx"
$Username = "xxx#xxx.com"
$Password = "xxx"
$ReqTokenBody = #{
Grant_Type = "Password"
client_Id = $clientID
Client_Secret = $clientSecret
Username = $Username
Password = $Password
Scope = "https://graph.microsoft.com/.default"
}
$TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $ReqTokenBody
Get Calendar Events:
$apiUrl = "https://graph.microsoft.com/v1.0/groups/xxxxxxxxxx/calendarview?startdatetime=$mystartdate1&enddatetime=$myenddate1&orderby=start/DateTime ASC&top=100"
$Data = Invoke-RestMethod -Headers #{Authorization = "Bearer $($Tokenresponse.access_token)"} -Uri $apiUrl -Method Get
$Groups = ($Data | select-object Value).Value
#$Groups | Format-Table subject, start -AutoSize
$Groups | Select-Object -Property subject, Start, End
If I authenticate by Password Grant Type then it displays the results.
However if I authenticate by Client Credentials Grant Type then it throws following error:
Invoke-RestMethod : {
"error": {
"code": "ErrorAccessDenied",
"message": "Access is denied. Check credentials and try again.",
"innerError": {
"request-id": "cc111097-c8c2-4a35-af21-52cbbced33b7",
"date": "2019-11-29T09:37:51"
}
}
}
At line:10 char:9
+ $Data = Invoke-RestMethod -Headers #{Authorization = "Bearer $($Token ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
With the Client Credentials Grant Type I have no problem getting results from
$apiUrl = "https://graph.microsoft.com/v1.0/users/"
$apiUrl = 'https://graph.microsoft.com/v1.0/groups'
$apiUrl = "https://graph.microsoft.com/v1.0/devicemanagement/manageddevices"
Am I doing something wrong or the client credentials authentication cannot pull the calendar events.
When using the client credential flow to get the access token for Microsoft Graph, the Application permission in your AD App -> API permissions is needed.
But in this case, the Application permission is not supported for the List calendarView API. Without this permission, the token you got will not be able to call this API successfully.

Resources