Search code examples
azurepowershelloauth-2.0azure-functions

Oauth Authentication Token fails in powershell but not in Postman


I have the following logic in my powershell script that attempts to get a auth/bearer token:

$token = curl --location --request POST 'https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token' `
--form 'grant_type=client_credentials' `
--form 'client_secret=$DEPLOYMENT_CLIENT_SECRET' `
--form 'client_id=$DEPLOYMENT_CLIENT_ID' `
--form 'resource=https://management.azure.com'

the error I see:

PS /workspaces/testproject> ./curltest.ps1
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   981  100   419  100   562   1557   2089 --:--:-- --:--:-- --:--:--  3646
===========
{"error":"invalid_request","error_description":"AADSTS901002: The 'resource' request parameter is not supported.\r\nTrace ID: 5b54cd7f-6b2d-40fc-9122-7b3c26a56600\r\nCorrelation ID: asdf-asdf-asdf-asdf-\r\nTimestamp: 2022-05-04 19:22:06Z","error_codes":[901002],"timestamp":"2022-05-04 19:22:06Z","trace_id":"asdf-asdf-asdf-","correlation_id":"asdf-asdf-asdf-asdf-asdf"}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0^C

So I remove the resource like this:

$token = curl --location --request POST 'https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token' `
--form 'grant_type=client_credentials' `
--form 'client_secret=$DEPLOYMENT_CLIENT_SECRET' `
--form 'client_id=$DEPLOYMENT_CLIENT_ID' 
#--form 'resource=https://management.azure.com'

But the error I see now is this:

PS /workspaces/testproject> ./curltest.ps1
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1000  100   563  100   437   2025   1571 --:--:-- --:--:-- --:--:--  3597
===========
{"error":"invalid_request","error_description":"AADSTS90014: The required field 'scope' is missing from the credential. Ensure that you have all the necessary parameters for the login request.\r\nTrace ID: asdf-asdf-asdf-asdf-asdf\r\nCorrelation ID: asdf-asdf-asdf-asdf-asdf\r\nTimestamp: 2022-05-04 19:23:11Z","error_codes":[90014],"timestamp":"2022-05-04 19:23:11Z","trace_id":"asdf-asdf-asdf-asdf","correlation_id":"asdf-asdf-asdf-asdf","error_uri":"https://login.microsoftonline.com/error?code=90014"}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0^C

In Postman, I'm able to do this: enter image description here

I can add / remove the resource param. Either way, I get a token. The tenant id, client id and client secret all match what's being used in the powershell script.
If I plug the token generated using POSTMAN into the script and use it to curl GET call my home grown azure fn, it works.

I'm sure it's something simple I'm missing. Any help would be appreciated


Solution

  • The reason that you're seeing a success in Postman, is because you're using 2 different endpoints.

    In Postman you're using the v1 endpoint, https://login.microsoftonline.com/{tenant_id}/oauth2/token

    In PowerShell you're using the v2 endpoint https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token

    It seems that for v2, the resource parameter was replaced with scope

    Try replacing your resource parameter with scope = "https://management.azure.com/.default"

    I'm able to obtain a token using Invoke-RestMethod

    $params = @{                
        Uri    = "https://login.microsoftonline.com/$($tenant_id)/oauth2/v2.0/token"
        Method = "POST"
        Body   = @{
            client_id     = $client_id
            client_secret = $client_secret
            grant_type    = "client_credentials"
            scope         = "https://management.azure.com/.default"
        }
    }
     
    $connection = Invoke-RestMethod @params