I want to use an App Registration, ClientApp
, to use a REST API endpoint, for which I've created a second App Registration, APIApp
.
I want to acquire a token with ClientApp
using delegated permissions instead of app roles, but the following code isn't working.
I'm using the instructions in Microsoft Learn to target /oauth2/devicecode
then /oauth2/v2.0/token
:
# https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code
[guid]$TenantId = "..."
[guid]$ClientAppId = "..."
[guid]$APIAppId = "..."
$deviceCodeBody = @{
client_id = $ClientAppId
scope = "api://$APIAppId/MyData.Read.All offline_access"
}
$deviceCodeRequest = Invoke-RestMethod `
-Method Post `
-Uri "https://login.microsoftonline.com/$tenantId/oauth2/devicecode" `
-ContentType 'application/x-www-form-urlencoded' `
-Body $deviceCodeBody
Write-Host "`n$($deviceCodeRequest.message)"
$tokenBody = @{
grant_type = "urn:ietf:params:oauth:grant-type:device_code"
device_code = $deviceCodeRequest.device_code
client_id = $ClientAppId
}
$tokenRequest = $null
while ([string]::IsNullOrEmpty($tokenRequest.access_token)) {
try {
$tokenRequest = Invoke-RestMethod `
-Method Post `
-Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" `
-ContentType 'application/x-www-form-urlencoded' `
-Body $tokenBody
}
catch {
$errorMessage = $_.ErrorDetails.Message | ConvertFrom-Json
# If not waiting for auth, throw error
if ($errorMessage.error -ne "authorization_pending") {
Write-Host "Error: $($errorMessage.error_description)" -ForegroundColor Red
exit 1 # Exit script
}
Start-Sleep -Seconds 1
}
}
I could get the necessary token easier with azure-cli
but then I'd require app roles (app permissions) for ClientAppId
. I prefer using delegated user permissions like in this example:
[guid]$TenantId = "..."
[guid]$ClientAppId = "..."
[string]$ClientSecret = "***"
[guid]$APIAppId = "..."
az login `
--allow-no-subscriptions --tenant $TenantId `
--service-principal -u $ClientAppId -p $ClientSecret `
--query accessToken --output tsv
$accessToken = az account get-access-token `
--scope 'api://$APIAppId/.default' `
--query accessToken --output tsv
Can you please explain what I'm doing wrong? When I use the devicelogin method I get the following error
AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Should I get the token for ClientAppId
in any other way?
I got same error message, When I ran the script which you provided:
To resolve this error, Configure Authentication Tab of Client-App
like below:
Now, Generated Client Secret for Client-App
:
Use below modified script:
[guid]$TenantId = "<tenant-id>"
[guid]$ClientAppId = "<client-app-id>
[guid]$APIAppId = "<API-app-ID>"
# Step 1: Request device code
$deviceCodeBody = @{
client_id = $ClientAppId
scope = "api://$APIAppId/MyData.Read.All offline_access"
}
$deviceCodeRequest = Invoke-RestMethod `
-Method Post `
-Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/devicecode" `
-ContentType 'application/x-www-form-urlencoded' `
-Body $deviceCodeBody
Write-Host "`n$($deviceCodeRequest.message)" # Prompt the user
# Step 2: Poll for token
$tokenBody = @{
grant_type = "urn:ietf:params:oauth:grant-type:device_code"
device_code = $deviceCodeRequest.device_code
client_id = $ClientAppId
client_secret = "<client-secret>" # Replace with your actual client secret after configuring authentication tab
}
$accessToken = $null
while ($accessToken -eq $null) {
try {
$tokenResponse = Invoke-RestMethod `
-Method Post `
-Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" `
-ContentType 'application/x-www-form-urlencoded' `
-Body $tokenBody
$accessToken = $tokenResponse.access_token
} catch {
$errorMessage = $_.ErrorDetails.Message | ConvertFrom-Json
if ($errorMessage.error -ne "authorization_pending") {
Write-Host "Error: $($errorMessage.error_description)" -ForegroundColor Red
exit 1
}
Start-Sleep -Seconds 2
}
}
# Step 3: Use the access token
Write-Host "`nAccess Token:`n$accessToken"
Response:
When I decoded this generated access token at https://jwt.ms :