Hero Banner

Secure Application Model

Learn and ask questions on how to implement secure application model

Level 3 Contributor

Exchange Online and the Secure App Model

Am I missing something in that I cannot see a way to implement it. A lot of my automation relies on the ability to see things like transport rules and Exchange configuration settings that come out of the Exchange Online Powershell cmdlets.


Is this stuff exposed in the Graph API or ANY API? I can't see it anywhere. Are there plans to update the Exchange Online Powershell Module to support the Secure App Model before 1st of August?


Hi @Gavsto


Currently the Exchange Online PowerShell module does not support DAP when MFA is enabled. You can find more information about this here. The Exchange Online team is working to resolve this issue as quickly as possible. Unfortunately I do not have any additional information to share just yet. As I learn more I will be sure to share it with you.

Level 6 Contributor

Sorry for jumping in and for the late reply (I was on holidays when this was announced early July and I'm just back now).


So what is the solution for Partners using Delegated Admin to access our clients' Exchange Online via PowerShell? In another thread it was mentioned that we shoould create an Admin in each client's tenant and use that - use 100's of separated admin accounts? That seems like a worse solution.


I have various automations that run daily that need to connect to all our client's Exchange Orgs to make changes, I can't even envision a simple method to manage all the changes so we can still access all clients alonng with separate usernames/passwords for each.


Can we avoid the issue with Azure AD IP Based Conditionl Access policies and still be in compliance? (all connections come from our secured servers)


Or will the Exch Online team have this fixed by Aug 1st?!


Level 3 Contributor

I am keen to get an answer to this too because I have heavy reliance on Exchange Powershell cmdlets across hundreds of different clients too.


@Gavsto and @sansbacher our documentation has been updated to include details for a workaround for this limitation. You can find the details for this workaround here. The Exchange Online team is actively developing a solution for this limitation, but it will be some time before it is available. We will be sure to keep everyone informed as progress is made.

Level 6 Contributor

Thanks @idwilliams


So I'm clear: the workaround is to create a new AzureAD user in OUR (CSP/Partner) tenancy, assign it AdminAgents privleges (in the PartnerCenter) and not using it to perform an interactive login?


How is that going to work when MS enforces the technical requirement that ALL accounts in our CSP/Partner tenantancy have MFA enabled with the Baseline Policies? Or is the fact that it isn't logged into interactively mean it doesn't have the MFA policy applied and will continue to work with Exchange Online Delegated Admin Privileges? Essentially "fly under the radar"? [I actually have an account now I use only from unattended scripts, so it may continue working? Or must it be an all new account?]


This is confirmed to work? Will this account also work to connect to AzureAD?


A previous suggestion had been to create an Exchange Admin in client/customer tenant and manage Exch Online that way - is that no longer suggested?


@sansbacher, the workaround for Exchange Online will continue to function with technical enforcement.  The account you created for unattended scripting will continue to function as well as long as the account has never been used to complete an interactive login.  With that said, this workaround should be viewed only as a temporary workaround.  Support for delegated admin priviledges will be added to the Exchange Online powershell module in the future and this workaround will be removed.  Your unattended scripts should be modified to support the secure application model to ensure long-term support.


The previous suggestion of creating an account in each client/customer tenant is no longer recommended.

Level 6 Contributor

Thank you @daokeefe - I appreciate the response (though I have to say that in general I agree with @Gavsto regarding how all this has been handled, esp. as it relates to the Exch Online PowerShell)


I have an existing unattanded service account, it was created a while ago so I don't know if it was ever logged into interactively, it hasn't been recently since MFA was turned on. If it fails to work I will create another one.


I hope that when proper Delegated Admin Privileges are added to the Exchange Online PowerShell module that we'll get advance notice before the work-around is disabled so that we can test the new module with the Secure App Model and our scripts (since we won't know exactly how it works until you deliver it).

ALSO: how will we be notified when the ExO module has been updated?


NOTE: I have tested the Secure App Model, and I found it works with the older MsOnline module, but not the newer AzureAD module. I hope that is fixed too. (and add the MFA controls to AzureAD at the same time)


Sorry for my late reply, I was on holidays - but I'm back now!



@sansbacher once the issue Exchange Online PowerShell is resolved, we will post an announcement through this community. Also, there will be a number of additional mechanisms we use to communicate this release. Once we get closer to the update being release, I will be able to comment more percisely on how this announcement will be handled. 


As it relates to the Azure AD PowerShell module, I have confirmed it does work with the Secure Application Model. If you can let us know what issues you encountered we will be glad to see if we can help resolve the issue. 

Level 3 Contributor

There is no update yet for the Exchange Online modules, making it very difficult to run automated jobs except for the workaround we've been given before - Which has also been removed from the docs so it is safe to assume it is no longer allowed to use this workaround.


We require automated access to the Exchange Online PowerShell, using delegated permissions to script specific events without an engineer touching these automated PowerShell scripts and logging in under each tenant.


Next to this - other modules such as the Azure-AD module do work when using the secure app model for our own tenant, but not for delegated access tenants. The documentation is also -extremely- unclear how to set this up for all tenants under our administration via delegated access, but so far every reaction Microsoft is stating to look at the documentation.


It seems like this entire exercise has been a panicked move by Microsoft and there is no clear path for automators, CSPS, and MSP's to actually access all the resources (Exchange online, Microsoft Teams, Azure AD) of all the delagated tenants we have access to using automation via PowerShell. 


Please update the documentation to match the exact use cases of the Secure Application Model to show how to access resources in delegated tenants, with examples of each module that supports the Secure App Model, because right now I believe this is not possible due to a Microsoft oversight.


@KelvinTegelaar : Reg. Exchange Online I'm currently researching the updated status - so far the workaround mentioned (use an account which never has been used for an interactive logon) does still work. There are several updates to the documentation in the works, afaik this aspect is moved to a new article which has not been published yet.


For the other questions, like AzureAD module - it is possible to get specific guidance when raising an advisory request, Partner with Action Pack, Silver or Gold competency level get advisory hours as technical benefit and then the scenario and potential solution can be discussed 1:1 - see aka.ms/technicaljourney or the "PreSales and Deployment Planning" support options at partner.microsoft.com/support. Also an email to askpts@microsoft.com does work to raise a case in this team (While I'm from this team, I miss the required expertise to answer right here and we can invest more time into this when you raise a ticket).


However, it is true that there might still be services/scenarios which do not play well with the MFA requirements and you are also correct that security requirements had to be introduced before there is a perfect answer from every related product team.



Kind regards, Janosch (Note: Leaving role as of March 2023, don't expect further answers. Connect with me via LinkedIn: https://linkedin.com/in/janoschulmer)

And I was just informed about an updated article on this, available here: https://docs.microsoft.com/en-us/powershell/partnercenter/multi-factor-auth?view=partnercenterps-2.0#exchange-online-powershell 


Edit#2: This method requires you to go through interactive sign-in once to get the refresh token, then you can get access token for each customer without the need to go through interactive sign-in again. This method does not support the before mentioned workaround where you create a user account that was never used for an interactive sign-in. 


Edit: New/recent ExO Powershell version should be downloaded for this.

Kind regards, Janosch (Note: Leaving role as of March 2023, don't expect further answers. Connect with me via LinkedIn: https://linkedin.com/in/janoschulmer)
Level 3 Contributor

Awesome! this is a fantastic and welcome update.


Just to clarify: We have to get a refresh token per tenant under our administration, and not just a single refresh token for our tenant, which should have delegated access to each of the other locations? 


Thanks Janosch, This is good news and I am glad you're also acknloweding that we got limited in our work a bit by the sudden move to the secure application model.


Yes, the way the token based authentication works is that there is a token for each customer tenant: however, you do the interactive sign-in only once to get the token for your Partner Center user, with this token you can get the token for each customer tenant without going through the interactive sign-in again - so similar to other scenarios with secure app model. 

Kind regards, Janosch (Note: Leaving role as of March 2023, don't expect further answers. Connect with me via LinkedIn: https://linkedin.com/in/janoschulmer)
Level 3 Contributor

@KelvinTegelaar @JanoschUlmer 


Do either of you have any example of how you would utilise this from an automation perspective. Is an interactive login still required each time a script is run?


Example - lets say I want to run through every mailbox with Get-EXOMailbox at every business we support (100s of different tenants). What would be the best method to use?

There's a DelegatedOrganization switch listed at https://docs.microsoft.com/en-gb/powershell/module/exchange/powershell-v2-module/connect-exchangeonline?view=exchange-ps but it doesn't work. If I do Connect-ExchangeOnline -DelegatedOrganization "myclient.onmicrosoft.com", it prompts me for login, and once logged in I run Get-EXOMailbox and I end up with my own tenants mailbox and not that of the delegated org.

Level 3 Contributor

Opened an issue, as it seems the ParterCenter module is broken and does not generate credentials for Exchange right now: https://github.com/microsoft/Partner-Center-PowerShell/issues/186

Level 3 Contributor

So the module has been updated, but there is still a problem with the documentation. 


I've run the following:

$token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716' -Scopes 'https://outlook.office365.com/.default' -Tenant 'xxxx-xxxx-xxxx-xxxx' -UseDeviceAuthentication

and I have a refresh token generated for Exchange, so far so good. Now if I follow the rest of the documentation I'll execute the following to create a per-tenant refresh code and start a session:

$refreshToken = '<RefreshTokenValue>'
$upn = '<UPN-used-to-generate-the-refresh-token>'

$token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716' -Credential $credential -RefreshToken $refreshToken -Scopes 'https://outlook.office365.com/.default' -ServicePrincipal -Tenant 'ID-OF-DELEGATED-TENANT'

but $credential has not been set anywhere, when trying the applicationid+secret I get the error:

New-PartnerAccessToken : AADSTS7000215: Invalid client secret is provided.

When trying the UPN+Refresh token I get the same error. I believe the documentation is missing a little bit.



Just forwarding the ad hoc response from an expert:


The root cause for this issue is that the Credential and ServicePrincipal parameter should not be used. It is included in our documentation because with everything else the Azure AD application exists in the partner's tenant instead of a foreign one. If they remove those parameters it should work as expceted
Kind regards, Janosch (Note: Leaving role as of March 2023, don't expect further answers. Connect with me via LinkedIn: https://linkedin.com/in/janoschulmer)
Level 3 Contributor



See the following blog for a ready-made solution: https://www.cyberdrain.com/connect-to-exchange-online-automated-when-mfa-is-enabled-using-the-secureapp-model/


It took some work, and some argueing but with the current version everything is working. @JanoschUlmer Thank you for your help, The documentation will still need some updates but my blog contains those for anyone looking right now.



Level 6 Contributor

@KelvinTegelaar Stellar work, thanks so much! I've been somewhat absent from all this MFA/CSP stuff since before Technical Enforcement on Nov 18th - busy with other stuff. But your blog post basically had everything I needed!


I was able to connect to Exchange Online of one of our Customers using Delegated Permissions without any user interaction! I now have to update all my scripts...


But I did have a problem with Azure AD, connecting to Azure AD of Customers we have delegated admin rights to. But I worked it out.


Connecting to our CUSTOMERS with Msol is fairly straight forward, use the Connect-MsolService commands as listed at the end of Kelvin's blog post to connect to YOUR (eg. CSP) Msol service, then Get-MsolPartnerContract will list all YOUR Customers you have DELEGATED permissions to. You can then use a foreach ($customer in $Customers) {} loop.
Inside the foreach you can then use any Msol command AND specify their TenantID, eg: Get-MsolUser -TenantId $Customer.TenantId will show the CUSTOMER'S users, not yours. You need to add -TenantId to all Msol commands since you are connected to your Msol service endpoint (but you have delegated permissions to your Customers)


For AzureAD it was slightly more complicated: I could get MY internal (eg. CSP) Users, but not my CUSTOMER's Users that I had Delegated permissions to, I would get an error like:
Get-AzureADUser : Error occurred while executing GetUsers
Code: Request_BadRequest
Message: Invalid domain name in the request url.


The solution for Azure AD is:
Connect to AzureAD as listed in Kelvin's blog post, this will connect to YOUR (eg. CSP) Azure AD
Get all your Customers that you have Delegated Admin rights to with: Get-AzureADContract
Then Disconnect-AzureAd (will disconnect from your AzureAD)
You will need (just like the Exch Online code): $upn = 'UPN-Used-To-Generate-Tokens'
Then in your foreach ($customer in $Customers) {} loop you must obtain NEW AAD and Graph Tokens for the Customer's TenantId, such as:
$CustAadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $customer.CustomerContextId

# And
$CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $customer.CustomerContextId
Finally connect to the CUSTOMER'S AzureAD (to which you have Delegated rights):
Connect-AzureAD -AadAccessToken $CustAadGraphToken.AccessToken -AccountId $upn -MsAccessToken $CustGraphToken.AccessToken -TenantId $customer.CustomerContextId
[Note that $customer.CustomerContextId is the CUSTOMER's TenantID, which is obtained from Get-AzureAdContract (when connected to YOUR Azure AD, the first time)]

You can now run commands like Get-AzureAdUser or Get-AzureAdDomain and it will show the CUSTOMER's users/info.
Disconnect-AzureAd at the end of the loop (from the Customer's AzureAD)


More script updating for me! But at least I can now use the Secure App Model with MFA to connect to my CSP Azure AD, get all Customers, and then connect to each of my Customers' Azure AD + Exch Online to do unattended scripting.


Thanks for finally getting this all sorted out!


PS: This is using the most recent AzureAD, Msol, and PartnerCenter modules (,, and 3.0.1 respectively). No need at this point for the new preview Exchange Online V2 PowerShell module. Maybe in the future it'll make things easier.


Level 3 Contributor

@sansbacher Really appreciate the update!

I've been delving in to this further today but I am still hitting a brick wall.

I have my Azure AD Application created. I have my RefreshToken created. I know these work OK because delegated access works to both Exchange and MSOnline.

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID 
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID 

Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken

Works great!


When it comes to AzureAD I am completely stuck. Previously my problem was that I couldn't get access to my client's AzureAD. I used to run Get-AzureADUsers and just see my own staff. Now I can't even see my own staff.

Get-AzureADUser : Error occurred while executing GetUsers 
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
RequestId: Redacted
DateTimeStamp: Mon, 06 Jan 2020 22:35:16 GMT
HttpStatusCode: Forbidden
HttpStatusDescription: Forbidden
HttpResponseStatus: Completed

At line:1 char:1
+ Get-AzureADUser
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-AzureADUser], ApiException
    + FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.GetUser

This is the same for any AzureAD command.

The code I am using:

$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $ApplicationCredential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $TenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $ApplicationCredential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $TenantID

Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -MsAccessToken $graphToken.AccessToken -TenantId $TenantID -AccountId $UPN

The UPN I am adding in is the UPN of the user who performed the initial consent when creating the application (my e-mail address).

Incidentally, Connect-AzureAD does return something when run:

Account                     Environment TenantId                             TenantDomain                         AccountType
-------                     ----------- --------                             ------------                         -----------
myladmin@emailaddress.co.uk AzureCloud  MyTenantIDHere    MyTenantIDHere AccessToken

Anyone have any idea how I even start to diagnose this?

I've created the application from scratch. I've tried different Global Admins. I've ran out of ideas. I wonder if MS have any input either, @JanoschUlmer