Skip to main content

Using the Office365/Exchange 2016 REST API part 2 buiding an Admin Runner using AppOnly tokens

This is part 2 in my REST series in which we will look at AppOnly tokens. These are the Tokens you would look to use when you want to write an application or script that would access every mailbox in an Office365 Tenant.  For an Admin or DevOps person looking at what they might want to do with the new REST API this is useful when your looking to write something that will tweak a config setting on all Mailboxes to comply with a certain Organization policy (no matter how insane) or do some custom Item task that isn't supported in any of the Admin cmdlets.

To simplify AppOnly tokens as much as I can they are an Oauth Access token that are requested using Certificate Authentication. Then depending on what Application permission scopes have been allowed for the app in Azure eg


your script or app will be able to access that particular Mailbox data across all the Mailboxes within your tenant. In EWS if you understood how impersonation worked this is a kind of an equivalent but a lot better from a security perspective. Eg if your just writing a script that needs to keep contacts in sync in a Mailbox (which I've seen and done many times) then you can just assign the "Read and write contacts in all mailboxes" scope for your application and nothing else and that's all your application can do. With Impersonation you effectively gave full access to Mailbox and which could then be potentially exploited and was much derided by security people in general.

Setup
 
There is bit of setup to do before you can use this which can be little complicated but I'll try to simplify the best I can.

1. You need to first create a Web Application registration within your tenant using the Azure Management Console (note a native app won't work for this). https://docs.microsoft.com/en-us/azure/active-directory/active-directory-app-registration . For this type of application the SignIn and Auth url isn't important as we are going to be using certificate auth so you can just use something like https://192.168.100.100:8000 eg


2. Configure the Application permissions for what you want your application to do eg the below screen again. For my test app I'm going to be using the "Read All Mailbox Setting" scope to create a script that read the Oof Message and timezone setting from all mailboxes passed in. Delegated permission aren't valid for this type of App as they won't be scoped for the this type of Access token.


Make sure you click save down the bottom to ensure the changes you make are committed

3. Create a self signed certificate that will be used to sign the JWT (Java Web Token) requests. To make this easy in my Rest module I've create a cmdlet to do this using the default New-SelfSignedCertificate Powershell cmd. However this will only work on Windows 10 because it requires the -provider switch which isn't available on early O/S. Alternatives you can use are MakeCert which there is an example of in https://msdn.microsoft.com/en-us/office/office365/howto/building-service-apps-in-office-365 or you could use OpenSSL

If you want to use my cmdlet you need to use it like

Invoke-CreateSelfSignCert -CertName "yourCertNameMakeitdescriptive" -CertFileName c:\temp\yourcertFile.pfx -KeyFileName c:\temp\KeyCreds.txt

where CertName should be self explanatory, CertFileName is the filename for your certificate (you could chose to leave It in the windows CertStore but I've exported it to file for flexibility). -KeyFileName is a temporary text file that will hold the configuration information that needs to be copied in to the Application manifest in Azure in step 4.

4. Update the Application manifest, from the Azure Console where you configuration the application permissions in step2 you need to select the download manifest from the Manage Manifest option at the bottom of the console eg

Once you have download the manifest you need to open that in a Text editor (or VSCode if you have it) and locate the keycredentials entry


If you then open the KeyFileName that was created with Invoke-CreateSelfSignCert in step 3 and cut and paste the all the content and replace the [] in Keycredentials in the manifest you downloaded eg it should look something like this

 
Make sure when your pasting the data you don't wipe the comma after the value as you will get a parse error when you try to upload the manifest. So once you save those change you click upload Manifest from the Manage Manifest button in the Azure console.

5. The last thing you want to do while in the Azure console is get your tenant ID information there are a number of ways to do this but the easiest is outlined in https://support.office.com/en-us/article/Find-your-Office-365-tenant-ID-6891b561-a52d-4ade-9f39-b492285e2c9b  (just look at the URL when you modifying the application). You will need this TenantId for the Module Setup

PowerShell Module Setup

In my REST Script module I have a config section at the top that holds the information needed for generating the token. For App only tokens you need to setup the following variables

function Get-AppSettings(){
        param(
       
        ) 
  Begin
   {
            $configObj = "" |  select ResourceURL,ClientId,redirectUrl,ClientSecret,x5t,TenantId
            $configObj.ResourceURL = "outlook.office.com"
            $configObj.ClientId = "084adbb3-f70c-498f-97a3-464e1f444d9a"
            $configObj.TenantId = "1c3a18bf-da31-4f6c-a404-2c06c9cf5ae4"
            $configObj.ClientSecret = ""
            $configObj.x5t = "3Y5+FU8x2tZ8DudO479K71ILQF8="
            $configObj.ValidateForMinutes = 60
            return $configObj           
         }   
}

ResourceURL should be fine unless you want to access the Graph API

ClientId should be the ClientId of your Application in Manifest file you downloaded previously take the value from appId which should be the first line in the manifest

redirectURL isn't used for AppOnly token

TenantId should be set to the value you retrieved in step 5 above.

x5t should be set to the customKeyIdentifier that you pasted into the KeyCredentials in the manifest file.

Testing

Once you have all the configuration done to test if it is working you use the Get-AppOnlyToken cmdlet to create an app only token

$Token  = Get-AppOnlyToken -CertFileName c:\temp\certfile.pfx

If you then look at the contents of the $Token variable you should have either an error or a Token

Putting it to use

I've included one example report in the REST Module that will work with AppOnly tokens. This produces a report of Mailbox setting using the GetMailboxSetting op https://msdn.microsoft.com/office/office365/APi/mail-rest-operations#get-all-mailbox-settings

To run this you pass in a collection of Mailbox addresess you want to run the report against (eg you could produce this using Get-Mailbox) or use a CSV file or just using something like

$Mailboxes = @()
$Mailboxes += "one@domain.com"
$Mailboxes += "two@domain.com"

$report = Get-MailboxSettingsReport -Mailboxes $Mailboxes -CertFileName c:\temp\certfile.pfx
$report | Export-Csv -NoTypeInformation -Path c:\temp\mbreport.csv

The REST PowerShell module can be found here https://github.com/gscales/Powershell-Scripts/blob/master/RestHttpClientMod.ps1

Popular posts from this blog

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Gr...

Sending a Message in Exchange Online via REST from an Arduino MKR1000

This is part 2 of my MKR1000 article, in this previous post  I looked at sending a Message via EWS using Basic Authentication.  In this Post I'll look at using the new Outlook REST API  which requires using OAuth authentication to get an Access Token. The prerequisites for this sketch are the same as in the other post with the addition of the ArduinoJson library  https://github.com/bblanchon/ArduinoJson  which is used to parse the Authentication Results to extract the Access Token. Also the SSL certificates for the login.windows.net  and outlook.office365.com need to be uploaded to the devices using the wifi101 Firmware updater. To use Token Authentication you need to register an Application in Azure https://msdn.microsoft.com/en-us/office/office365/howto/add-common-consent-manually  with the Mail.Send permission. The application should be a Native Client app that use the Out of Band Callback urn:ietf:wg:oauth:2.0:oob. You ...

How to test SMTP using Opportunistic TLS with Powershell and grab the public certificate a SMTP server is using

Most email services these day employ Opportunistic TLS when trying to send Messages which means that wherever possible the Messages will be encrypted rather then the plain text legacy of SMTP.  This method was defined in RFC 3207 "SMTP Service Extension for Secure SMTP over Transport Layer Security" and  there's a quite a good explanation of Opportunistic TLS on Wikipedia  https://en.wikipedia.org/wiki/Opportunistic_TLS .  This is used for both Server to Server (eg MTA to MTA) and Client to server (Eg a Message client like Outlook which acts as a MSA) the later being generally Authenticated. Basically it allows you to have a normal plain text SMTP conversation that is then upgraded to TLS using the STARTTLS verb. Not all servers will support this verb so if its not supported then a message is just sent as Plain text. TLS relies on PKI certificates and the administrative issue s that come around certificate management like expired certificates which is why ...
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.