Hero Banner

Secure Application Model

Learn and ask questions on how to implement secure application model

Reply
Leon-anspired
Level 4 Contributor

MS Graph and Partner GDAP - access customer tenant via graph

I am trying to get some scripting ready for Granular Delegated Admin permissions that we are all forced to change to this year from DAP and really struggling to work out how to get this working to access customer tenants.

I have created an app in our CSP tenant with relevant permissions. Has relevant graph permissions (like directory.read.all) and partner center user impersonation.

Global admin has granted consent.

I can generate access tokens and connect to the graph for our own tenant. Along with querying contracts etc to get a list of all our customer tenants etc. However it seems impossible to connect to a customer MSGraph when using GDAP.

For a tenant that is still on DAP, I can use

https://login.microsoftonline.com/<customer tenant ID>/oauth2/v2.0/token

To get an access token and then the graph will respond their tenant.

But if I do the same for a tenant that has GDAP, I get:

"error": {
"code": "Authorization_IdentityNotFound",
"message": "The identity of the calling application could not be established.",
"innerError": {
"date": "2022-05-30T11:24:11",
"request-id": "aa4d75a5-03ed-4f5a-811d-e09e63e346ed",
"client-request-id": "aa4d75a5-03ed-4f5a-811d-e09e63e346ed"
}

 

The Azuread App service principal is in the group which has been given access to the tenant.
User management role so can access the msgraph to get a list of users. But just get the above error.

Struggling to find anything online and not sure where to go from here.

Hope someone has some insight into how to make this work.

1 ACCEPTED SOLUTION
ClaudioStallone
Level 6 Contributor

Hello @Leon-anspired@EliK@KoenHalfwerk@Glenndsq 

 

this week at the "CSP Security Updates and Q&A Session" the solution was presented as already explained by @JanoschUlmer here.

So this is now the Final solution to continue to access customer environments using Secure Application Model.

 

Here the further information:
Recording from the session
https://globalpbocomm.eventbuilder.com/event/66287/recording?source=GranularDelegatedAdminPrivilegesinCSPQASession

 

Documentation around the new variant for Secure Application Model
https://nwvpportalfiles.blob.core.windows.net/nwvp-portal-files/portals/46/accounts/15509/DAP%20to%20GDAP%20Application%20Consent%20and%20OBO-November-7.pdf

 

Registration for the "CSP Security Updates and Q&A Sessions"
https://globalpbocomm.eventbuilder.com/GranularDelegatedAdminPrivilegesinCSPQASession

View solution in original post

95 REPLIES 95
Leon-anspired
Level 4 Contributor

No, I think you are missing that MSGraph subscribedSkus/

Is a completely different response.

It is the equivalent of Get-MsolAccountSku

What I need is the equivalent of Get-Msolsubscription which gets the specific subscriptions which make up the total count of the sku's in the tenant.

sansbacher
Level 6 Contributor

Ahhh, okay that makes sense. We ARE Tier 1/Direct CSP, so I probably never noticed that certain APIs were only available to us. Sorry.

This is weird: "Get-MSOLSubscription does not have a retirement date currently so you can continue to use this API for now. In transitioning to MS Graph, our intention is to provide equivalent or improved functionality for all MSOL APIs and Powershell cmdlets (including lifecycle dates). Please stay tuned for announcements specific to MSOL and MS Graph licensing APIs."

From: https://github.com/microsoftgraph/microsoft-graph-docs/issues/17500

That makes it seem like the MSol module (MSOnline) doesn't have a retirement date, which means the AAD Graph doesn't either. I know it has been delayed and whatnot, but I thought it was still slated to be turned off.

BUT: even if it remains (for now, until they transition licensing functionality into MS Graph) the MSol/MSOnline module does NOT appear to work with GDAP - so what will we do even if AAD Graph/MSol is still "working", it won't be working for us? (I may be able to use Graph/PartnerCenter as a Direct/Tier 1, but most CSPs are Indirect/Tier2).

--Saul

JanoschUlmer
Microsoft

@EliK : OK, so you then use Invoke-RestMethod against the endpoints directly, not the PowerShell Module, no "Connnect-ExchangeOnline" I guess? 

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)
JanoschUlmer
Microsoft

I'm confident that this consent action will be required in the future. I'm not yet sure about:

 - The minimum role required to use the API to do the automatic consent (Cloud App Admin was confirmed by engineering, but I'm not 100% sure). 

 - the permissions which need to be requested when doing the automatic consent. In my example I used Read and AccessAsUser, which was sufficient since effective permission depend on the user permissions (via GDAP), but I did not yet get confirmation.

 

I'm also pushing hard to release documentation on this, fully agree that unexpected changes have a lot of impact.

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)
EliK
Level 2 Contributor

After adding and removing DAP relationship, it seems like I have most endpoints working with GDAP only. However, I cannot access Exchange at all with a PS session or the outlook.office365.com endpoint. the error I'm getting is "error":"interaction_required","error_description":"AADSTS50204: External user has not consented to the privacy statement... it would seem that the delegated user account that I used to create the exchange refresh token is not added with GDAP to the customers exchange environments.

For reference or anyone else running into errors, this is the code I used to add and consent to the app in the customer environment. I tried the PowerShell version you posted but was thrown errors. I've been messing with permissions, this is where I'm at for now. This works with GDAP I have not tested this with DAP but I assume it would for sure work (user and app are in GDAP group with every permission including global admin for now)

$PartnerHeaders = @{ Authorization = "$($PartnerToken.token_type) $($PartnerToken.access_token)" }
$Bodyjson = @{
displayName = "<APP NAME>"
applicationId = "<APP ID>"
applicationGrants = @(
@{
enterpriseApplicationId = "00000002-0000-0000-c000-000000000000" #Windows Azure Active Directory
scope = "Directory.ReadWrite.All,Directory.AccessAsUser.All"

},
@{
enterpriseApplicationId = "00000003-0000-0000-c000-000000000000" #Microsoft Graph
scope = "AuditLog.Read.All,DelegatedAdminRelationship.ReadWrite.All,Directory.AccessAsUser.All,Directory.ReadWrite.All,email,MailboxSettings.ReadWrite,offline_access,openid,Organization.Read.All,`
profile,Reports.Read.All,SharePointTenantSettings.ReadWrite.All,Sites.FullControl.All,Sites.ReadWrite.All,User.Read.All"

},
@{
enterpriseApplicationId = "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd" #Microsoft Partner Center
scope = "user_impersonation"

},
@{
enterpriseApplicationId = "797f4846-ba00-4fd7-ba43-dac1f8f63013" #Azure Service Management
scope = "user_impersonation"

},
@{
enterpriseApplicationId = "00000002-0000-0ff1-ce00-000000000000" #exchange
scope = "Exchange.Manage"

}

)
}
$Body = $Bodyjson | ConvertTo-Json -Depth 10
Invoke-RestMethod -Method Post -Headers $PartnerHeaders -uri "https://api.partnercenter.microsoft.com/v1/customers/<Customer tenant Id>/applicationconsents" -Body $Body -ContentType 'application/json'



Leon-anspired
Level 4 Contributor

I am pretty sure you still need a separate exchange token for the MS provided exchange online appid to connect to exchange online.

 

 

And if it helps here is the API details to add the consent.


Get your access token to partner center

 
Body
{
  "applicationId""<Client_ID of azuread app, or s365l prod app client_id if delegated admin>",
  "applicationGrants": [
    {
      "enterpriseApplicationId""00000003-0000-0000-c000-000000000000",
      "scope""Directory.Read.All"
    }
  ]
}
JanoschUlmer
Microsoft

@EliK : What Exchange PowerShell version are you using with secure app model? And how? Afaik for using access via tokens & as Partner only the v1 module would work, not the v2 and v3. For v3 it is recommend to use app-only with an app registered in customer tenant.

The error you are getting sounds like being caused by a Conditional access rule (Terms-Of-User policy) deployed in a customer tenant - does this happen for every customer?

 

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)
EliK
Level 2 Contributor

@JanoschUlmer I am testing with a single test tenant we have set up, and have been playing with both V1 (importing the exchange PS session) and V3 (the outlook.office.com/adminapi/beta endpoint). for both the starting point is generating an access token via the exchange refresh token.

I was successful with both, though I'm not sure exactly why. The oauth v1 endpoint still gives me the same error, however I am able to connect to both the v1 and v3 exchange endpoint using the oauth/v2.0/token endpoint.

this is the sample code that works for other DAP customers using the oauth2 v1 endpoint but does not work for my test GDAP client:

$RequestAccessTokenUri = "https://login.microsoftonline.com/$($Customer.tenantId)/oauth2/token"
$Resource = 'https://outlook.office365.com'
$Body = @{ client_id = 'a0c73c16-a7e3-4564-9a95-2bdf47383716'; resource = $Resource; refresh_token = $ExchangeRefreshToken; grant_type = 'refresh_token' }
$ExchangeAdminToken = Invoke-RestMethod -Method Post -Uri $RequestAccessTokenUri -Body $Body -ContentType 'application/x-www-form-urlencoded'

here is the code that does work using the oauth v2 endpoint:

 

$RequestAccessTokenUriV2 = "https://login.microsoftonline.com/$($Customer.tenantId)/oauth2/v2.0/token"
$scope = 'https://outlook.office365.com/.default'
$Body = @{ client_id = 'a0c73c16-a7e3-4564-9a95-2bdf47383716'; scope = $scope; refresh_token = $ExchangeRefreshToken; grant_type = 'refresh_token' }
$ExchangeAdminToken = Invoke-RestMethod -Method Post -Uri $RequestAccessTokenUriV2 -Body $Body -ContentType 'application/x-www-form-urlencoded'
ClaudioStallone
Level 6 Contributor

Thank you @JanoschUlmer, for your efforts here!

 

For us it is very important that we have a definitive solution here soon.

 

So that we can continue to administer those customers, who now only have a GDAP relationship, via the secure application model.

JanoschUlmer
Microsoft

@Leon-anspired : As mentioned, the "CPV API" is simply a method to deploy an app into a tenant and consent to it - documentation will be updated that this method does not only to CPVs, but any CSP Partner. So any Partner can deploy an app into the customer tenant. 

 

I agree that this new approach is a challenge reg. asking only for least privilege permission in the admin relationship, and I was surprised myself that there was a decision to change this. I also brought forward the concern that even though in day-to-day activities lesser permission would be suffice, for doing this one-time registration higher privileges are required. Given this I think there are these potential approaches:

  • Before migrating everything to GDAP, you use existing DAP to do the app deployment - and for new customers you do not only send the reseller relationship invite and the admin relationship invite, but a 3rd link for app registration (https://login.microsoftonline.com/{customertenant}.onmicrosoft.com/adminconsent?client_id={appid} ) so global admin of the customer does not only confirm the relationship, but also the app.
  • You set up two admin relationships - one with your standard, least privilege permissions, and another with just AppAdmin, but only for a few days duration, to be able to deploy the app within this timeframe.

Reg. the permissions -  I don't think there is another applicable role - e.g. App Developer can't do the consent, but I know that engineering is looking into this. Even the App Admin role is not fully tested, when you read the role reference you see that there are some important limitation reg. consent to graph permissions: https://learn.microsoft.com/en-us/azure/active-directory/roles/permissions-reference#application-administrator 

 

I fully agree that this change is a challenge in the automation approach for Partners. I will update the thread if there is something new to share about 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)
Leon-anspired
Level 4 Contributor

Thanks,

Appreciate the responses.
Are you confident enough to suggest this will be the way forward? I want to make sure it is right before we spent a bunch of time updating our code and developments. Just dont want it to all of a sudden change again and we have to redo our work 🙂

What you have provided does work and I am thankful for that as at least we are now not stuck at not being able to work.

JanoschUlmer
Microsoft

First update - registering the Partner app in the customer tenant will be required- this is based on security considerations to ensure Partner activities are being logged under the Partner identity. Stil not 100% confirmed, I don't have an ETA for the documentation. Just wanted to provide first information and how to work with it. Below is not brand new, it was always an option:

 

Adding the Partner app in the customer tenant, can be done non-interactively by the Partner, so when you have necessary permissions you don't need to ask any customer to click on "consent". There is an API to do an app consent on behalf of customers, see Control Panel Vendor APIs for customer consent - Partner Center app developer | Microsoft Learn (Which is available to CPVs, but also to other CSPs)

 

I also tested this using Partner Center PowerShell successfully, the respective cmdlet uses above mentioned API ,

Notes:

  • I did not test yet if adding the app works with "Application Admin" as least privilege roles (assigned via GDAP), as Global Admin it works
  • I did only test calling MgGraph PowerShell and AZ, nothing else.

 

 

$testCXID = "tenantID of a customer"

$SAMAppID = "AppID of the multi-tenant app for secure app model in Partner Center"


#Adding explicit consent in Customer tenant for SAM#

##Grants##
$ADGraphgrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$ADgraphgrant.EnterpriseApplicationId = "00000002-0000-0000-c000-000000000000"
$ADGraphgrant.Scope = "Directory.Read.All,Directory.AccessAsUser.All"
$MSGraphgrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$MSgraphgrant.EnterpriseApplicationId = "00000003-0000-0000-c000-000000000000"
$MSGraphgrant.Scope = "Directory.Read.All,Directory.AccessAsUser.All"
$AzureGrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$AzureGrant.EnterpriseApplicationId = "797f4846-ba00-4fd7-ba43-dac1f8f63013"
$AzureGrant.Scope = "user_impersonation"

 

##Adding App to customer###
New-PartnerCustomerApplicationConsent -ApplicationId $SAMAppId -ApplicationGrants @($ADgraphgrant, $MSGraphgrant, $AzureGrant) -CustomerId $testcxid -DisplayName "janoschutestsam2"

 

Note that I added the permissions scopes explicitly in the grants, it does not take over the permissions set for the app in the Partner. Above mentioned permissions should be sufficient - while they mention "Read" and not ReadWrite, you will get also write permission based on the permissions the calling user has - since it is delegated auth and "AccessAsUser" permissions.

 

Using above example, it is also possible to add the app registration in bulk for any managed customer.

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)
ClaudioStallone
Level 6 Contributor

Hello @Leon-anspired@EliK@KoenHalfwerk@Glenndsq 

 

this week at the "CSP Security Updates and Q&A Session" the solution was presented as already explained by @JanoschUlmer here.

So this is now the Final solution to continue to access customer environments using Secure Application Model.

 

Here the further information:
Recording from the session
https://globalpbocomm.eventbuilder.com/event/66287/recording?source=GranularDelegatedAdminPrivilegesinCSPQASession

 

Documentation around the new variant for Secure Application Model
https://nwvpportalfiles.blob.core.windows.net/nwvp-portal-files/portals/46/accounts/15509/DAP%20to%20GDAP%20Application%20Consent%20and%20OBO-November-7.pdf

 

Registration for the "CSP Security Updates and Q&A Sessions"
https://globalpbocomm.eventbuilder.com/GranularDelegatedAdminPrivilegesinCSPQASession

VNJoe
Level 6 Contributor

How is this marked as a solution?

sansbacher
Level 6 Contributor

Thanks for confirming this @ClaudioStallone !

 

I had tested DAP to GDAP migration (using the Bulk Migration Tool) back at the end of August 2022 and everything was fine - at least it appeared so.... But turned out NOT to be the case now. What I had done to test was: Confirm DAP permissions worked and that I had a local/customer Global Admin login, performed the GDAP migration with the Tool, removed DAP, confirmed I no longer had delegated access. I received errors like:

  • For Azure: New-PartnerAccessToken : AADSTS50020: User account '{EmailHidden}' from identity provider 'https://sts.windows.net/b169ca...'
  • For Azure AD it connected but threw: get-azureaduser : Error occurred while executing GetUsers Code: Authentication_Unauthorized
  • Exch Online: New-PSSession : [ps.outlook.com] Processing data from remote server ps.outlook.com failed with the following error message: [AuthZRequestId=d259daac-9....] The user UPN@domain.com isn't assigned to any management roles.

I then added the UPN@domain.com and our CSP Azure AD Partner Center App to the GDAP Group with the Global Admin role and retried: it all worked... back in August. 

 

I finally had a chance to test what @JanoschUlmer had posted, and what @KelvinTegelaar just confirmed: it no longer works. Now when I do the above I get the following error:

New-PartnerAccessToken : AADSTS65001: The user or administrator has not consented to use the application with ID 'f7282f04-our-app-ID...' named 'Our CSP Partner Center App Name'. Send an interactive authorization request for this user and resource.

 

At least for Azure AD, Azure, and MS Graph. Adding the UPN@domain.com to the GDAP Global Admin group does work for Exchange Online PowerShell but not the others.

 

So the solution is as Janosch posted, but here's what I did with a few notes/tweaks, and as Kelvin noted: this CPV API method can be done without any user-interaction with just the GDAP permissions. It only needs to be done once per Customer Tenant. 

 

Connect as per-normal: connect to your CSP AAD tenant, get all your Customers ($AllCustomers = Get-AzureADContract -All $True), disconnect your AzureAD.

 

Then, as you connect to each Customer tenant (eg: foreach ($Customer in $AllCustomers) { ... etc; etc; ...}) you will need to get AAD and Graph Tokens using New-PartnerAccessToken, wrap in a try/catch. If it FAILS with the above AADSTS65001 error, use the following:

 

# Connect to PartnerCenter. This is your CSP Secure App Model App ID, plus your long Refresh Token, and your Partner Center creds (App ID + the App's Secret)
Connect-PartnerCenter -ApplicationId $AzureADAppId -RefreshToken $RefreshToken -Credential $pcCreds

# Create the grants:
# Windows Azure Active Directory
$ADGraphgrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$ADgraphgrant.EnterpriseApplicationId = "00000002-0000-0000-c000-000000000000"
$ADGraphgrant.Scope = "Directory.Read.All,Directory.AccessAsUser.All"
# Microsoft Graph
$MSGraphgrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$MSgraphgrant.EnterpriseApplicationId = "00000003-0000-0000-c000-000000000000"
$MSGraphgrant.Scope = "Directory.Read.All,Directory.AccessAsUser.All"
# Windows Azure Service Management API
$AzureGrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$AzureGrant.EnterpriseApplicationId = "797f4846-ba00-4fd7-ba43-dac1f8f63013"
$AzureGrant.Scope = "user_impersonation"

# The DisplayName MUST match your CSP Secure App Model App Registration Name
$pcAppDisplayName = "Our Partner Center NativeApp Name"

# Add the App Consent in the Customer's tenant. Uses your Azure Secure App Model AppID and the Display Name,
# and the $Customer.CustomerContextId of the particular customer
New-PartnerCustomerApplicationConsent -ApplicationId $AzureADAppId -ApplicationGrants @($ADgraphgrant, $MSGraphgrant, $AzureGrant) -CustomerId $Customer.CustomerContextId -DisplayName $pcAppDisplayName

# Disconnect from PC
Disconnect-PartnerCenter

 

Then you can continue as before - retry the New-PartnerAccessToken to get the AAD and Graph Tokens for the Customer and it should continue and work! You can then connect to your Customer with delegated GDAP permissions as before.

 

Once connected to the Customer's AzureAD you can see your App as a Service Principal as Kelvin noted:

Get-AzureADServicePrincipal -All $true | where AppId -eq $AzureADAppId

 

It can be removed if you wanted to redo it. And the customer can see it in their Azure AD portal under Enterprise Applications, set Application Type = "All Applications" (or clear the filter). It appears with your DisplayName. So you probably want to name it something professional!

 

That will work for AzureAD, Azure (Az), and MS Graph (MgGraph). However it will NOT work for MSOnline (Msol) commands 😞

Where Get-MsolUser -All -TenantId $Customer.CustomerContextId would work for DAP, it no longer works for GDAP, it gives:

     Get-MsolUser : Access Denied. You do not have permissions to call this cmdlet

I don't know why, the Azure AD Graph GUID is in the list of permissions that @JanoschUlmer gave in his post. The well known App IDs don't list anything different, I may look into this (maybe there are additional permissions that can be granted?). I suppose it may be time to give up those commands... They're handy to get MFA info...

 

As Janosch noted, the Grants only request Read Access, but I confirmed that the permissions are whatever has been delegated, including write access.

 

Reminder: for Exchange Online (ExO) Remote PowerShell [the $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=etc,etc,etc" ; Import-PSSession $Session... stuff] you must add your UPN@domain.com (the UPN for the account your did your original Consenting to create the Secure App Model App Registration) to a GDAP Group with at least the Exchange Admin Role (I assume, I just used Global Admin for my tests). 

 

Other notes:

  • The video recording Claudio referenced needs to be signed up for, it's the session from November 07, 2022 8:00 AM Mountain Time. Sign up for event 66287, and then you can watch the video. It's only the first few 10-15 mins that are about this. It's not super informative.
  • The PDF Claudio and Kelvin linked to: DAP to GDAP Application Consent and OBO-November-7.pdf has some info, esp. on the second method Kelvin mentioned.
  • Via API, instead of New-PartnerCustomerApplicationConsent it may be possible to use the /applicationconsents end-point, but I have not tried it.
  • Janosch's original comment on this is worth reading for more info.

 

I hope this helps a few people. I really hope this gets documented somewhere by Microsoft.

   --Saul

 

aconn21
Level 4 Contributor

How have you got this to work with mggraph?

I followed the instructions after converting a customer from DAP to GDAP. Azure and Azure AD modules are working fine, but with mggraph if I run get-mguser I get 'Insufficient privileges to complete the operation'

Here is an example of how I'm connecting to mggraph (v2)

$App_Cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $AppID, $AppSecret
Connect-MgGraph -ClientSecretCredential $App_Cred -TenantId $CustomerTenantID

aconn21
Level 4 Contributor

Never mind, I saw the thing about app only auth not being supported in GDAP. This worked:

$graphToken = New-PartnerAccessToken -ApplicationId $AppID -Credential $App_Cred -RefreshToken $RefreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $CustomerID
$sectoken = $graphtoken.AccessToken | ConvertTo-SecureString -AsPlainText -Force
Connect-MgGraph -AccessToken $sectoken

 

aconn21
Level 4 Contributor

I can also confirm this doesnt appear to be true for mggraph: "the Grants only request Read Access, but I confirmed that the permissions are whatever has been delegated, including write access."

In the case of mggraph I had to specify all the scopes I needed for that customer in the grant when running New-PartnerCustomerApplicationConsen.

For example I had DeviceManagementServiceConfig.ReadWrite.All set correctly in the API permissions in my partner tenant. This did not flow through to the customer I changed to GDAP. Hence this command failed to work: Get-MgDeviceManagementDeviceEnrollmentConfiguration

So I removed the consent then redid it with DeviceManagementServiceConfig.ReadWrite.All added to the scope of the grant for Microsoft Graph. After that, the command worked fine.

sansbacher
Level 6 Contributor

Hi again @aconn21 ,

 

I have the New-PartnerCustomerApplicationConsent Consents working, and can connect to AzureAD, Azure, and Exchange Online [so my scripts are basically able to work as they did before GDAP/ExO App ID retirement] and now I'm looking and moving to MS Graph.

 

Are you saying you had to add many (or perhaps ALL?) of the MS Graph permissions to your MS Graph grant you're pushing into each Customer? Right now I'm just using something like this, basically what I detailed here:

 

 

# Assumptions: $Customer is from Get-AzureADContract (via your CSP Partner Tenant), $AzureADAppId is the ClientID of your Secure App in your CSP/Partner tenant, and $pcCreds is that ClientID + AppSecret, and of course $RefreshToken is your normal Refresh Token. $AzureADDisplayName is the Name of your Secure App in your Azure AD.

# Connect to your CSP Partner Center
Connect-PartnerCenter -ApplicationId $AzureADAppId -RefreshToken $refreshToken -Credential $pcCreds

# Microsoft Graph
$MSGraphgrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$MSgraphgrant.EnterpriseApplicationId = "00000003-0000-0000-c000-000000000000"
$MSGraphgrant.Scope = "Directory.Read.All,Directory.AccessAsUser.All,DelegatedAdminRelationship.ReadWrite.All"

# Plus Grants for:
# Windows Azure Active Directory, "00000002-0000-0000-c000-000000000000","Directory.Read.All,Directory.AccessAsUser.All"
# Windows Azure Service Management API, "797f4846-ba00-4fd7-ba43-dac1f8f63013", "user_impersonation"
# Office 365 Exchange Online, "00000002-0000-0ff1-ce00-000000000000", "Exchange.Manage"

# Add the Consent for the Customer (creates the Enterprise App)
New-PartnerCustomerApplicationConsent -ApplicationId $AzureADAppId -ApplicationGrants @($ADgraphgrant, $MSGraphgrant, $AzureGrant, $ExchangeGrant) -CustomerId $Customer.CustomerContextId -DisplayName $AzureADDisplayName

 

 

But for $MSGraphgrant.Scope are are you including ALL or MANY Graph permissions? Did you find you had to you?

 

Also, after we found we needed to add the 'Office 365 Exchange Online' Grant, I wonder if there are any other ones we should add? I see there's lots of MS App IDs.

 

I did see somewhere, in my googling (I can't remember where) that someone added the 'Microsoft Partner Center', so I added:

# Microsoft Partner Center
$PartnerGrant = New-Object -TypeName Microsoft.Store.PartnerCenter.Models.ApplicationConsents.ApplicationGrant
$PartnerGrant.EnterpriseApplicationId = "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd"
$PartnerGrant.Scope = "user_impersonation"

But I don't know if it's strictly needed? I don't think it can't really hurt...

 

I imagine every time we find something new we need to add to the Consent Grant we need to remove/re-add the Enterprise App (Service Principle). I already ran into a case where I got an AADSTS65001 error when trying to get the Exch Online Token -- I ended up having to remove and re-ad the Consent Grant and it worked fine. (I assume it was from messing around with my Sec App's API Permissions trying to get things working...)

 

I saw that @rvdwegen mentioned he used New-MgOauth2PermissionGrant to adjust the permissions Granted - so I assume it's maybe possible to update things after the fact. But I'd like to get this close to "final" before we fully migrate to GDAP for all our clients.

 

Currently I have been able to create the Consent Grants for all my customers, DAP or GDAP, except one, where New-PartnerCustomerApplicationConsent returns some JSON error "Authorization_RequestDenied" and the message "Insufficient privileges to complete the operation". I'm hoping that's a one-off and I'll address it later.

 

   --Saul

rvdwegen
Level 5 Contributor

Grants/permissions do indeed need to exist on both ends, your tenant and the customer tenant.

I've since moved to doing everything with REST API, including the enterprise app consent.

 

Very rough example:

 

    $ApplicationGrants = @(
        [pscustomobject]@{
            EnterpriseApplicationId = "00000002-0000-0000-c000-000000000000"
            Scope = "Directory.Read.All,Directory.AccessAsUser.All"
        } # Azure AD Graph Powershell API
        [pscustomobject]@{
            EnterpriseApplicationId = "00000003-0000-0000-c000-000000000000"
            Scope = "Files.ReadWrite.All,Application.Read.All,Application.ReadWrite.All,AuditLog.Read.All,BitlockerKey.Read.All,Channel.Create,Channel.Delete.All,Channel.ReadBasic.All,ChannelMember.Read.All,ChannelMember.ReadWrite.All,ChannelMessage.Edit,ChannelMessage.Read.All,ChannelMessage.ReadWrite,ChannelMessage.Send,ChannelSettings.Read.All,ChannelSettings.ReadWrite.All,ConsentRequest.Read.All,Device.Command,Device.Read,Device.Read.All,DeviceManagementApps.ReadWrite.All,DeviceManagementConfiguration.ReadWrite.All,DeviceManagementManagedDevices.PrivilegedOperations.All,DeviceManagementManagedDevices.ReadWrite.All,DeviceManagementRBAC.ReadWrite.All,DeviceManagementServiceConfig.Read.All,DeviceManagementServiceConfig.ReadWrite.All,Directory.AccessAsUser.All,Directory.ReadWrite.All,Domain.Read.All,Group.ReadWrite.All,GroupMember.ReadWrite.All,Mail.Send,Mail.Send.Shared,Member.Read.Hidden,Organization.ReadWrite.All,Policy.Read.All,Policy.ReadWrite.AccessReview,Policy.ReadWrite.ApplicationConfiguration,Policy.ReadWrite.AuthenticationFlows,Policy.ReadWrite.AuthenticationMethod,Policy.ReadWrite.Authorization,Policy.ReadWrite.ConditionalAccess,Policy.ReadWrite.ConsentRequest,Policy.ReadWrite.CrossTenantAccess,Policy.ReadWrite.DeviceConfiguration,Policy.ReadWrite.ExternalIdentities,Policy.ReadWrite.FeatureRollout,Policy.ReadWrite.MobilityManagement,Policy.ReadWrite.PermissionGrant,Policy.ReadWrite.SecurityDefaults,Policy.ReadWrite.TrustFramework,PrivilegedAccess.Read.AzureResources,PrivilegedAccess.ReadWrite.AzureResources,ReportSettings.ReadWrite.All,Reports.Read.All,RoleManagement.ReadWrite.Directory,SecurityActions.ReadWrite.All,SecurityEvents.ReadWrite.All,SecurityIncident.Read.All,SecurityIncident.ReadWrite.All,ServiceHealth.Read.All,ServiceMessage.Read.All,SharePointTenantSettings.ReadWrite.All,Sites.FullControl.All,Sites.Manage.All,Sites.Read.All,Sites.ReadWrite.All,Team.Create,Team.ReadBasic.All,TeamMember.ReadWrite.All,TeamMember.ReadWriteNonOwnerRole.All,TeamSettings.Read.All,TeamSettings.ReadWrite.All,TeamsActivity.Read,TeamsActivity.Send,TeamsAppInstallation.ReadForChat,TeamsAppInstallation.ReadForTeam,TeamsAppInstallation.ReadForUser,TeamsAppInstallation.ReadWriteForChat,TeamsAppInstallation.ReadWriteForTeam,TeamsAppInstallation.ReadWriteForUser,TeamsAppInstallation.ReadWriteSelfForChat,TeamsAppInstallation.ReadWriteSelfForTeam,TeamsAppInstallation.ReadWriteSelfForUser,TeamsTab.Create,TeamsTab.Read.All,TeamsTab.ReadWrite.All,TeamsTab.ReadWriteForChat,TeamsTab.ReadWriteForTeam,TeamsTab.ReadWriteForUser,ThreatAssessment.ReadWrite.All,UnifiedGroupMember.Read.AsGuest,User.ManageIdentities.All,User.Read,User.ReadWrite.All,UserAuthenticationMethod.Read.All,UserAuthenticationMethod.ReadWrite,UserAuthenticationMethod.ReadWrite.All,Vulnerability.Read,offline_access,openid,profile"
        } # Graph API
        [pscustomobject]@{
            EnterpriseApplicationId = "797f4846-ba00-4fd7-ba43-dac1f8f63013"
            Scope = "user_impersonation"
        } # Windows Azure Service Management API
        [pscustomobject]@{
            EnterpriseApplicationId = "00000002-0000-0ff1-ce00-000000000000"
            Scope = "Exchange.Manage"
        } # Exchange Online
        [pscustomobject]@{
            EnterpriseApplicationId = "fc780465-2017-40d4-a0c5-307022471b92"
            Scope = "Vulnerability.Read"
        } # Windows Defender ATP
        [pscustomobject]@{
            EnterpriseApplicationId = "00000003-0000-0ff1-ce00-000000000000"
            Scope = "AllSites.FullControl"
        } # Office 365 SharePoint Online
        [pscustomobject]@{
            EnterpriseApplicationId = "48ac35b8-9aa8-4d74-927d-1f4a14a0b239"
            Scope = "user_impersonation"
        } # Skype and Teams Tenant Admin API
    )

foreach ($Grant in $ApplicationGrants) {

        $AppBody = @{
            ApplicationId = $SAMAppId
            ApplicationGrants = @(
                $Grant
            )
        } | ConvertTo-Json -compress

            $consentRequest = Invoke-WebRequest -Method 'POST' -Uri "https://api.partnercenter.microsoft.com/v1/customers/$($tenant.TenantID)/applicationconsents" -Headers $header -Body $AppBody -UseBasicParsing

}

 

sansbacher
Level 6 Contributor

Thanks @rvdwegen !

 

I'll definitely add those other Enterprise Application IDs, and that looks like a fairly complete list of Graph Permissions. I think I can add them to the Customer Tenant, and then add them individually - as needed - to my Secure App, and avoid having to update/recreate the Customer Apps. It's simple to update my Secure App and then I'm not having more permissions than needed.

 

Can I ask: for what reasons/benefits did you switch to REST API access instead of using the PartnerCenter or Microsoft.Graph (MgGraph) PowerShell modules? I was thinking of using the MgModule for the very common stuff (Users, Groups, etc) and raw API access for anything else - so I can perhaps avoid having to deal with pagination, etc. Or is there some reason to go straight to REST APIs for everything now? (I'm just starting to transition all my Msol + AzureAD stuff to Graph, so I'd rather start off on the right foot if I can!)

 

For your REST API headers, what are you using to redeem your RefreshToken for an AccessToken? Ie. the equivalent to:

New-PartnerAccessToken -ApplicationId $AzureADAppId -Credential $pcCreds -RefreshToken $RefreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $AzureADTenantId
 
I assume you use that in your $header, with Authorization = "bearer $AccessToken"
 
Any other tips/suggestions?
  --Saul