Use Azure AD App-only token to consume SPO REST API

Frank Chen
8 min readDec 24, 2016

--

As SPO and Azure AD are getting popular, it’s possible to request token from Azure AD and use that token to communicate to SPO. When the business users are adapting SPO, they found out the traditional timer job hosted on SharePoint on premise is no longer supported on SPO. A standalone console application hosted on Azure WebJob or on premise environment became a solution to replace a traditional SharePoint server-side timer job. Since SPO is using oAuth2 authentication, the right authentication becomes to a critical part when you design those timer jobs. A traditional timer job running under SharePoint domain usually needs to deal with couple scenarios:

  1. Be able to elevate privilege to perform tasks which require higher permissions.
  2. Be able to on behalf of an account to perform tasks which is only allowed by that account.

As we know that SPO supports App ID approach for both scenarios, however App ID approach doesn’t allow the developers to communicate to other online services like Office Graph and Exchange online because App ID approach is based on ACS. This limitation obviously prevents developers to integrate their SPO applications with O365. As Azure AD introduced the client credentials grant flow, Azure AD App-only token approach is an ideal approach to allow applications to communicate to multiple O365 services using a same token as long as your Azure AD App is allowed to.

Differ than a traditional app which uses Azure AD for authentication, a app using App-only token approach presents its client credentials to the Oauth2 token issuing endpoint and in return gets an access token that represent the application itself without any user information. It allows app to communicate to resource using that app-only token. This approach doesn’t need an app to get a refresh token because when access token expires, it just needs to communicate back to OAuth2 token endpoint to get a new one. Let’s dive in to see how to make that happen.

Prepare the certificate

In order to make this approach working, Azure AD App requires a certificate to be created for the trust between Azure AD and the actual consumer. For this case, the Azure AD is using a certificate’s public key and the actual consumer application is using a certificate’s private key for the trust creation. Even though a production certificate is required, a self-sign certificate is ok for this purpose. You can use the below steps to create a self-sign certificate:

  1. Run the following command to create a certificate under “My” certificate store
makecert -r -pe -n “CN=TestCN AzureADAppOnlyCert” -b 12/01/2016 -e 12/30/2020 -len 2048 -ss my

2. Open Certificate Snap-in and export your certificate to AzureADAppOnlyCert.cer

3. Export your certificate with private key to AzureADAppOnlyCert.pfx and enter password.

4. Open PS command and run the following PS Command. When ask certificate, enter the certificate *.cer file which you just export it.

$certPath = Read-Host “Enter certificate path (.cer)”$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2$cert.Import($certPath)$rawCert = $cert.GetRawCertData()$base64Cert = [System.Convert]::ToBase64String($rawCert)$rawCertHash = $cert.GetCertHash()$base64CertHash = [System.Convert]::ToBase64String($rawCertHash)$KeyId = [System.Guid]::NewGuid().ToString()$keyCredentials =‘“keyCredentials”: [{“customKeyIdentifier”: “‘+ $base64CertHash + ‘“,“keyId”: “‘ + $KeyId + ‘“,“type”: “AsymmetricX509Cert”,“usage”: “Verify”,“value”: “‘ + $base64Cert + ‘“}],’$keyCredentialsWrite-Host “Certificate Thumbprint:” $cert.Thumbprint

5. You should have keyCredentials content show there.

Create Azure AD App

Once you have certificate and related information ready, you are able to create a Azure AD App for your App-Only authentication. The following steps mention how:

  1. Go to https://portal.azure.com
  2. Click “Azure Active Directory” on the left menu.
  3. Click “App Registrations”->”Add”. Type the following values:

Name: AzureADAppOnlyTest

Application Type: Web app/API

Sign-on URL: https://azureadapponlytest. Since you are going to test your console application which doesn’t have sign on url, you can just put whatever name here.

4. Go back to “App Registration” blade and click “AzureADAppOnlyTest” Azure AD App, click “Manifest”, the manifest.xml will be shown on the right. Click “download”, save and open up the manifest file. Copy “keyCredentials” value which you got from “Prepare the Certificate Step5” and paste to “keyCredentials” in manifest file. Save the file and upload the file back to Azure AD via click “Upload” button.

5. Go back to “AzureADAppOnlyTest” Azure AD App blade and click “Settings”->”Required permission”->”Add” to add a permission.

6. Select “Office 365 SharePoint Online(Microsoft SharePoint)”->Click “select” button at “Select an API” step.

7. Select “Have full control of all site collections” permission under “Application Permissions” section-> click “Select” button in “Select permissions” step. NOTE: it’s import to select the permission under “Application Permissions” section since this is for app-only token request.

8. Click “Done” button after that.

9. If you are Azure AD Admin and would like to do an admin consent, you can click “Grant Permissions” to grant to the permissions to your tenant level. If you are not Azure AD Admin, you have either ask your Azure AD Admin to consent or provide a click to consent. Otherwise, your Azure AD app won’t be able to get token with correct roles definitions inside the token. For he detail, you can reference to my troubleshooting section.

10. Now you have your Azure AD App configured. Remember to record the following setting for following usage:

11. Application ID

12. You .pfx certificate location.

App-only console application

After you create a Azure AD App, you are able to create a windows console application to communicate to a SPO site via app-only token.

  1. Open up Visual Studio 2015 and create a windows console application.
  2. Install ADAL.Net through Nuget. Open “Manage Nuget Package” and install the following packages:
  • “Microsoft.IdentityModel.Clients.ActiveDirectory”: ADAL.Net package.
  • “Newtonsoft.Json”: JSON.Net package

3. Right click project and click “Add”->”New Item”, and select a JSON file. Copy the following content to there. Our sample application is going to read Azure AD connection information from there. Make sure:

  • “resourceUrl” points to the REST API you want to use.
  • “certificatePath” point to the right *.pfx file
  • “certificatePassword” points to the right private key of the certificate.
{“tenantId”: “[tenant id]”,“clientId”: “[clientid]”,“resourceId”: “https://[tenantname].sharepoint.com/",“resourceUrl”: “https://[tenantname].sharepoint.com/_api/web/Lists/getbytitle('[listname]')",“certficatePath”: “..\\..\\cert\\AzuerADAppOnlyTest.pfx”,“certificatePassword”: “[cert private key]”}

4. Copy the following code to the program.cs. Hit F5, you should be able to

Troubleshooting

Things are not easy when you communicate to Azure AD and it became to more complicated when you are working at an enterprise environment because of security limit. I’ll list some of the tips to help you address the problems you might have to deal with.

The most common problem is “StatusCode: 401, ReasonPhrase: ‘Unauthorized’”. One day one of my colleagues is using the exactly same code as mine and the code was working on his development tenant. But it was failed in our UAT teanant. The issue is Azure AD consent process depends on who creates Azure AD for what kind of permissions. As we know that, anyone can access Azure AD to create a Azure AD App. It actually had different processes to consent the permission based on who create the Azure AD App and what permission the Azure AD App was requesting. Normally, you will see “Requires Admin” for the most of the Application Permission when you select permission from Azure AD portal. If you find out “Requires ADMIN” as yes, it means you need admin consent. See the screenshot below

There are couple situations we need to talk about regarding consent processes:

  • If you are Azure AD Admin and create a Azure AD App, when you first access your app and you should be asked to consent. Once you consent, your application should be working as you expect. The reason behind is because you are AAD admin, once you consent, the app was consent by admin. The permission you app was asking was granted. This situation happens a lot when you are working for your own development tenant. This is somehow the reason why your app had no problem for your development tenant, but got 401 issue when you deploy your app to different tenant which you don’t have admin permission.
  • If you are non-admin for Azure AD, after you create a Azure AD App and need to use App-only token for some of SPO function, you need Azure AD Admin to consent your permission request. Without admin consent, the access token you requested from App-only approach wouldn’t include a role definition for the permission you asked (I will explain later how to investigate token itself). Your Azure AD App will return 401. You can either ask your Azure AD admin to consent that from Azure AD portal through the following screen(“Grant Permissions” button) or provide an admin consent link for your application to ask admin to consent from your application. This scenario is the most annoy part.

How do you know if your application was consented successfully?

To ask this question, you have couple ways to verify that.

  1. Go to Azure Portal->Azure AD->Enterprise Applications->All Applications blade, find out your application and click “Permission” tab. Make sure the “Application” scope permission was consented by your admin already.

2. When you have your access token after you called await authenticationContext.AcquireTokenAsync(setting.ResourceId, cac), you can check your token content on website http://jwt.calebb.net. The following screenshot is an example for getting Outlook permission. If you configure application permission for SharePoint to have “Have full control of all site collections” permission, you need to see the role section to show “Site.FullControl.All”.

I hope you enjoy this sample, for a complete sample code, please reference to AppOnlySPOSample

--

--

Responses (2)