Managed IT provider | San Francisco | LookingPoint

RBAC the Truck Up! Exchange Online RBAC for Applications: Secure App Permissions

Written by Ryan Alibrando | Jun 10

Don’t Give Apps the Keys to the Kingdom: Granular Control with RBAC (Role Based Access Control) for Applications in Exchange Online

When you set up a third-party app to talk to Exchange (in Enterprise Applications or App Registrations), Azure lets you set permissions to ALL mailboxes and calendars. You grant the app Mail.Read or Calendars.ReadWrite, and suddenly that app has permission to poke around in every single mailbox in your organization (yep, even the CEO).

Application Access Policies are available, but those only limit the mailboxes your app has access to without being able to limit the type of access to those mailboxes.

RBAC for Applications in Exchange Online gives us the ability to grant different permissions to different mailboxes and is meant to replace Application Access Policies.

The Best of Both Worlds

Let’s say you have an app running on your website that checks your sales team’s calendars and sends an email from your marketing mailbox with a calendar invitation that books the first opening on a sales member’s calendar. Your app will need Mail.Send permission to just the marketing team mailbox and calendar.readwrite for your sales team. It is a *REALLY* good idea to only give specific permissions to specific mailboxes and/or calendars that are needed. What’s great is that it works in addition to the Graph API access you’ve already granted. Think of it as a double-lock system. Entra ID gives the app the "key" to the building, but Exchange RBAC decides which "rooms" (mailboxes) that key can actually open. There is no GUI for RBAC for Applications, so if you’re ready to use some powershell, let’s lock down our apps!

 

The Short Version

I’ll step through each of these, but if you just want a high level view, here’s what we’re going for.

  1. Verify versions
    1.    Powershell 5
    2.    Powershell 7
    3.    Microsoft.Graph module
    4.    ExchangeOnlineManagement module

  2. Gather App Info
    1.    Object ID (id)
    2.    Application ID (appid)

  3. Step through the RBAC Process
    1.    Define principal(app) for Exchange
    2.    Configure Group and get distinguished name (optional)
    3.    Create Scopes
    4.    Create Assignments
    5.    Test


 

The Long Version

When I first tried this out, the PowerShell versions and modules I was using to go through this process were in a weird state where the new authentication process required PowerShell 7, but the Exchange tools were using older calls requiring PowerShell 5. Please believe me when I say verifying your versions of PowerShell, Microsoft.Graph, and ExchangeOnlineManagement are as important as understanding the RBAC process. With Microsoft constantly updating these tools, it’s a good idea to check for updates regularly as well. Please save yourself from my pain!

The "Pre-Flight" Checklist: PowerShell Requirements & Installation

If you’re running Windows, there’s a good chance you’re toggling between Windows PowerShell 5.1 (part of the OS) and PowerShell 7.x (the standalone application).

      • OS Support: Windows 10/11 or Windows Server 2016 and up. If you're on Linux or macOS, you’re strictly in the PowerShell 7 camp. (Full transparency: I did not test this on Linux or Mac, so if you go down that road and find this helpful, but missing something for your environment, please add a note here for anyone else that may come along and benefit from your experience.)

    • Running as Administrator: I’d recommend running your windows as administrator for this initial validation and setup portion. Once you start connecting to Graph and Exchange, it’s not necessary though.

Windows 11 running minimum versions of PoSh 5.1.26100.7920 or 7.5.4 will set you up for success. I’ll take screenshots of this process side by side (5 on the left, 7 on the right) so you can see the action.

    • .NET requirements:
      •    PowerShell 5.1: Requires .NET Framework 4.7.2 or higher.
      •    PowerShell 7.4+: Newer module versions (like EXO V3.5+) are built on .NET 8.0.
      •    Verify with dotnet --version
      •    .net versions can be updated by downloading from https://dotnet.microsoft.com/en-us/download


              • PowerShell Modules:
                •    The "Helper" Modules:
                  •       The latest PowerShellGet and PackageManagement modules will ensure you can get what you need if you don’t have it.

          • Verify with
            • Get-module -name PowerShellGet
            • Get-module -name packagemanagement

          • Upgrade with
            • Install-module -name PowerShellGet
            • Install-module -name PackageManagement

         


        Step-by-Step Installation

          • The “Working” Modules:
            •    Verify at least these versions of the Microsoft.Graph and ExchangeOnlineManagment modules.
              •       Get-module -name “Microsoft.Graph”
              •       Get-module -name “ExchangeOnlineManagement”

  • To Install/Update without having to deal with verification prompts, you can use the following commands:
    •    Install-Module -Name Microsoft.Graph -Force -AllowClobber
    •    Install-Module -Name ExchangeOnlineManagement -Force -AllowClobber

 

Quick note on -Force & -AllowClobber switches:

    • Force (Overwrite Module):
      • Purpose: Forces installation if the same module version is already installed, or reinstalls the module over an existing one.
      • Scenario: You need to update or repair a module that is already present.

    • AllowClobber (Overwrite Commands):
      •    Purpose: Allows the module to install even if it conflicts with commands (functions or aliases) that are already loaded in the session from a different module.
      •    Scenario: You are installing a module that contains a command with the same name as one you already have

    • You also have the option to uninstall-module before installing the new version, or leaving off the switches if you want to see any prompts.
    • More info on all the install-module switches are here

 

  • A little verification goes a long way in saving you time over the long run. Let’s just double-check the versions you have with the following command.
    • Get-InstalledModule | Where-Object { $_.Name -match "ExchangeOnline|Microsoft.Graph" } | Select-Object Name, Version

  • ***NOTE*** Remember that if you install a module in PowerShell 5.1, it doesn't automatically show up in PowerShell 7. They live in different neighborhoods. Run the installation commands in the specific version of PowerShell you plan to use for your scripts.

 

The Setup: Gather Your Information

Close your administrative window and open a regular powershell window before performing these next steps. First, you’ll need to grab some info from the Entra ID side. Specifically, you need the AppId and the ObjectId.

GUI:

Be sure to get this info from the Enterprise Application section, NOT the App Registrations

 

In the GUI it looks like this:

 THIS GIVES YOU THE WRONG OBJECT ID:  

CLI:

You can also use the Microsoft Graph PowerShell module to find these quickly:

!!! Important Note on Assembly Version Clash !!! (THIS MAY SAVE YOUR SANITY)

Shared identity libraries can cause RuntimeBroker errors, NullReferenceException, or a MissingMethodException.

In Powershell 7, connect to ExchangeOnline BEFORE connecting to MgGraph to use the same window, otherwise, open two separate windows to avoid the clash.

In Powershell 5, you’ll need to open two separate windows, one to connect to Exchange, and another to connect to MgGraph

 

PowerShell

# Connect to Graph

Connect-MgGraph -Scopes "Application.Read.All"

 

# Find your service principal

Get-MgServicePrincipal -Filter "DisplayName eq 'YourAppName'" | Select-Object DisplayName, Id, AppId

# Make it easy on yourself and set some variables

$ObID = get-mgserviceprincipal -filter "DisplayName eq 'App That Needs Exchange Access'" | Select-Object Id

$AppID = get-mgserviceprincipal -filter "DisplayName eq 'App That Needs Exchange Access'" | Select-Object AppId

The Actual Work: Let’s Create Some Stuff!

Our prep is done! Now that you have everything you need, you can start working with Exchange Online.

 

***NOTE***

get-mgserviceprincipal” is part of the Microsoft.Graph module

New-ServicePrincipal” is part of the ExchangeOnlineManagement module

Although they’re referring to the same information, we need to define our principal (or app) in Exchange so it knows what to apply the RBAC permissions to.

 

Step 1: Create the Service Principal Pointer

After connecting to Exchange, we’ll tell it that this Entra app exists.

Connect-ExchangeOnline

New-ServicePrincipal -AppId <Your-App-ID> -ObjectId <Your-Object-ID> -DisplayName "My Scoped App"

( <Your-App-ID> would be $AppID if you set the variable, otherwise it’s the Application ID from the GUI )

( <Your-Object-ID> would be $ObID if you set the variable, or the Object ID from the GUI )

As you can see, even if you try to set it up with a different name, you can only create one service principal per app ID.

Step 2: Define Your Scope

This is where the magic happens. You can create a "Management Scope" to filter exactly which mailboxes the app can touch. For example, if you want to limit access to users in a specific department, you would do something like the following. You can create multiple management scopes to handle mailboxes and/or calendars, and you can use various filters to use other aspects of the Exchange objects.

New-ManagementScope -Name "Marketing Mailboxes" -RecipientRestrictionFilter "Department -eq 'Marketing'"

 

Step 3: Make the Assignment

Now, tie it all together. You assign a specific "Application Role" (like Application Mail.Read) to your Service Principal, restricted by the scope you just made.

New-ManagementRoleAssignment -App <Your-Service-Principal-Object-ID> -Role "Application Mail.Read" -CustomResourceScope "Marketing Mailboxes"

 

The "Devil in the Details" (Troubleshooting)

As with anything in the world of IT, it’s rarely a straight-line process. I ran into a couple of head-scratchers while testing this out that might save you some hair-pulling:

 

Final Thought

Moving to Application RBAC might feel like an extra step, but the security payoff is massive. In an era of OAuth phishing and credential theft, "least privilege" isn't just a best practice—it's a survival tactic.

Next time you’re onboarding a new tool that asks for "read everything" permissions, take five minutes to set up an RBAC scope. Your future self (and your security auditor) will thank you.

LookingPoint offers multiple IT services if you’re interested. Want more information, give us a call! Please reach out to us at sales@lookingpoint.com and we’ll be happy to help!