AzureFunctions, PowerShell, MS Graph and AppOnly permission

In a previous blog post, I wrote about connecting to Microsoft Graph with Resource Owner grant.

That particular authentication scheme is for delegate permissions.  So the function, utilizing an account's username/password, is performing actions as that user.

I'm revisiting that post today and instead talk about App-Only Permissions, and the steps are very similar, and to some may be easier.


Register App-Only

Head into the New Azure Portal.

Add "Read and write all groups" permission under "Application Permissions"

You should see this:

"1 Application Permission"

Hit the Grant Permission button here.

And set up a Client Secret

Nearly there, one more step we need to make the registered app allow implicit flow.

Hit the Manifest button, change oauth2AllowEmplicitFlow property to true, hit save.

Copy the Application ID - this is the Client ID.

On the first page of Azure AD properties, grab the Directory ID



You now have:

  • Directory ID (Tenant ID)
  • Application ID (Client ID)
  • Key (Client Secret)
  • And consent for your app has been granted.


PowerShell Code


$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$client_id = "44da3f20-fc0b-4f90-8bb1-54b1d50e3ecf";
$client_secret = $env:CS2;
$resource = "";

$authority = "$tenant_id";
$tokenEndpointUri = "$authority/oauth2/token";
$content = "grant_type=client_credentials&client_id=$client_id

$response = Invoke-WebRequest `
    -Uri $tokenEndpointUri `
    -Body $content `
    -Method Post `


The small difference between this time and the previous blog is now we are using AppOnly permissions.  The grant_type is client_credentials.  And you don't need to supply username/password.  The clientid/clientsecret pair is sufficient.


The whole thing

$name = "group-name-here"

$client_id = "44da3f20-fc0b-4f90-8bb1-54b1d50e3ecf";
$client_secret = $env:CS2;
$tenant_id = "26e65220-5561-46ef-9783-ce5f20489241";
$resource = "";

$authority = "$tenant_id";
$tokenEndpointUri = "$authority/oauth2/token";
$content = "grant_type=client_credentials&client_id=$client_id&client_secret=$client_secret&resource=$resource";

$response = Invoke-WebRequest -Uri $tokenEndpointUri -Body $content -Method Post -UseBasicParsing
$responseBody = $response.Content | ConvertFrom-JSON
$access_token = $responseBody.access_token

# $body = Invoke-RestMethod -Uri "" -Headers @{"Authorization" = "Bearer $access_token"}
# $body | ConvertTo-JSON

# POST - this creates groups
$body = @{"displayName"= $name; "mailEnabled"=$false; "groupTypes"[email protected]("Unified"); "securityEnabled"=$false; "mailNickname"=$name } | ConvertTo-Json 
$body = Invoke-RestMethod `
    -Uri "" `
    -Headers @{"Authorization" = "Bearer $access_token"} `
    -Body $body `
    -ContentType "application/json" `
    -Method POST
$body | ConvertTo-JSON

There are no other dependencies - authenticate and calling MS Graph is really that simple - two web requests!


The default "Owner"

Usually, the user that created the group becomes the Owner of the group.

In the Delegate Permission example in the last blog, the group is created with my user account and I'm the owner.

In the Application-Only Permission example in this blog, the group is created with the app account and there is no user owner!