Search code examples
powershelloauth-2.0azure-active-directoryjwtmicrosoft-graph-api

Unauthorized (401) listing synchronization jobs for service principal in MS Graph API


I am trying to use MS Graph API to configure Azure AD Connect Cloud Sync from these instructions but I am having trouble calling this endpoint in Powershell using client credentials:

https://graph.microsoft.com/beta/servicePrincipals/{SERVICE_PRINCIPAL_ID}/synchronization/jobs

I can successfully call this using the Graph Explorer, but no luck using Application permission and authentication with a client secret in Powershell. I get 401 Unauthorized error. I can call other endpoints like:

https://graph.microsoft.com/beta/servicePrincipals/{SERVICE_PRINCIPAL_ID}  # no /synchronization/jobs at the end

The application has the API permissions: Directory.ReadWrite.All and Application.ReadWrite.OwnedBy (Application) The permissions has been granted by the admin:

enter image description here

Below is the detail of the code I use to authenticate:

$Body = @{
    'tenant' = $TenantId
    'client_id' = $ClientId
     'scope' = 'https://graph.microsoft.com/.default'
    'client_secret' = $ClientSecret
    'grant_type' = 'client_credentials'
}

$Params = @{
    'Uri' = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
    'Method' = 'Post'
    'Body' = $Body
    'ContentType' = 'application/x-www-form-urlencoded'
 }

$AuthResponse = Invoke-RestMethod @Params

And this is how I call the endpoint:

$Headers = @{
    'Authorization' = "Bearer $($AuthResponse.access_token)"
}
$Params = @{
     Uri = "https://graph.microsoft.com/beta/servicePrincipals/{SERVICE_PRINCIPAL_ID}/synchronization/jobs"
     Method = 'Get'
     ContentType =  'application/json'
     Headers     = $Headers
 }
$res = Invoke-RestMethod @Params

And the error:

Invoke-RestMethod : The remote server returned an error: (401) Unauthorized

If I use the token from the Graph Explorer it works... My token from Powershell decoded contains this "roles" section but no "scp" like in the Graph Explorer token:

"roles": [
"Application.ReadWrite.OwnedBy",
"Directory.ReadWrite.All"
 ],

Full token obfuscated:

     {
    "aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/{TENANT_ID}/",
"iat": 1629836586,
"nbf": 1629836586,
"exp": 1629840486,
"aio": "{AIO}",
"app_displayname": "AppForAdConnect2",
"appid": "{APPID}",
"appidacr": "1",
"idp": "https://sts.windows.net/{TENANT_ID}/",
"idtyp": "app",
"oid": "{OID}",
"rh": "{RH}",
"roles": [
"Application.ReadWrite.OwnedBy",
"Directory.ReadWrite.All"
],
"sub": "{SUB}",
"tenant_region_scope": "NA",
"tid": "{TENANT_ID}",
"uti": "{UTI}",
"ver": "1.0",
"wids": [
"{WID}"
],
"xms_tcdt": 1584535155
}

Thank you for your help!


Solution

  • Ok so the solution was to add the role "Hybrid Identity Administrator" to the Service Principal or the User used to call the endpoint "synchronization/jobs". For some reason this application template needed this additional role and the API Permission enough is not enough.