{"id":782,"date":"2021-09-08T16:12:16","date_gmt":"2021-09-08T20:12:16","guid":{"rendered":"https:\/\/blog.markdepalma.com\/?p=782"},"modified":"2021-09-08T16:12:18","modified_gmt":"2021-09-08T20:12:18","slug":"using-application-permissions-and-client-credentials-grant-flow-with-hybrid-exchange-graph-api","status":"publish","type":"post","link":"https:\/\/blog.markdepalma.com\/?p=782","title":{"rendered":"Using Application Permissions (and client credentials grant flow) with Hybrid Exchange Graph API"},"content":{"rendered":"\n<p>We recently came across an application that uses Graph API and we wanted to start using it for some our on-prem mailboxes. Hybrid Graph API only supports delegated authentication flows and not application authentication flows. Just because something isn&#8217;t &#8220;<em>supported<\/em>&#8221; doesn&#8217;t mean you can&#8217;t make it work! There are two things that we&#8217;ll need to do to make this work.<\/p>\n\n\n\n<p>First, any internet-facing Exchange server will need to have &#8216;<strong>V1S2SAppOnly<\/strong>&#8216; OAuth support added. You can do this by adding <strong>V1S2SAppOnly<\/strong> to the <strong>OAuthHttpModule.Profiles<\/strong> key in the REST <strong>web.config<\/strong> (ex. <strong>&#8230;\\Program Files\\Microsoft\\Exchange Server\\V15\\FrontEnd\\HttpProxy\\rest<\/strong>). Once you add this value the key should look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"157\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1024x157.png\" alt=\"\" class=\"wp-image-784\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1024x157.png 1024w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-300x46.png 300w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-768x118.png 768w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-624x96.png 624w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image.png 1134w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>After this has been added either perform an <strong>iisreset<\/strong> or restart the &#8216;<strong>MSExchangeRestFrontEndAppPool<\/strong>&#8216; app pool in IIS for each server where you did this modification.<\/p>\n\n\n\n<p>The next step is to add the appropriate &#8216;<strong>AppOnlyPermissions<\/strong>&#8216; to the Microsoft Graph partner application in Exchange\/AD. First we&#8217;ll take a look at our Graph partner application:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Get-PartnerApplication | Where {$_.Name -like '*graph*'} | select *permissions* | fl\n\nAppOnlyPermissions : \r\nActAsPermissions   : {Mail.Read, Mail.Write, Mail.Send, Calendars.Read...}<\/pre>\n\n\n\n<p>The &#8216;<strong>AppOnlyPermissions<\/strong>&#8216; value should be blank. We need this to match the &#8216;<strong>ActAsPermissions<\/strong>&#8216; value. You&#8217;d think (and some other articles say) that you could just run <em>Set-PartnerApplication -AppOnlyPermissions<\/em>&#8230; but this was not a supported parameter for me. To set this we&#8217;ll have to edit AD directly. You&#8217;ll need to fire up something like <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.microsoft.com\/en-us\/previous-versions\/windows\/it-pro\/windows-server-2003\/cc773354(v=ws.10)?redirectedfrom=MSDN\" target=\"_blank\">ADSIEdit<\/a>, load the AD configuration partition, and drill down to your Exchange org and partner application object. The path should be something like:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">CN=Microsoft Graph,CN=Partner Applications,CN=Auth Configuration,CN=YOUR_EXCH_ORG,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=com<\/pre>\n\n\n\n<p>Once here you&#8217;ll need to open the &#8216;<strong>Microsoft Graph<\/strong>&#8216; object and copy the &#8216;<strong>msExchConfigurationXML<\/strong>&#8216; attribute value to the clipboard:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"616\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1-1024x616.png\" alt=\"\" class=\"wp-image-786\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1-1024x616.png 1024w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1-300x180.png 300w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1-768x462.png 768w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1-624x375.png 624w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-1.png 1201w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Next, we&#8217;ll use <a rel=\"noreferrer noopener\" href=\"https:\/\/notepad-plus-plus.org\/\" target=\"_blank\">Notepad++<\/a> and the <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/morbac\/xmltools\" target=\"_blank\">XML Tools<\/a> plugin to manipulate this. <strong>MAKE SURE YOU BACKUP THIS VALUE.<\/strong> We want to convert this to a nicely formatted XML output so that it is easy to work with. To do this we use the &#8216;Pretty print&#8217; option in XML Tools.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"584\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3-1024x584.png\" alt=\"\" class=\"wp-image-788\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3-1024x584.png 1024w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3-300x171.png 300w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3-768x438.png 768w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3-624x356.png 624w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-3.png 1195w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Once we have this we&#8217;ll need to duplicate all of the &#8216;ActAsPermissions&#8217; lines and then use find and replace to convert those tags to be &#8216;AppOnlyPermissions&#8217;. Doing this will create a set of application permissions based on our delegated permissions (ActAsPermissions).<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"883\" height=\"761\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4.png\" alt=\"\" class=\"wp-image-789\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4.png 883w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4-300x259.png 300w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4-768x662.png 768w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-4-624x538.png 624w\" sizes=\"auto, (max-width: 883px) 100vw, 883px\" \/><\/a><\/figure>\n\n\n\n<p>Once completed we need to linearize the output again so that we can copy it back into AD. We can use the &#8216;Linearize&#8217; option in XML Tools for this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"432\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5-1024x432.png\" alt=\"\" class=\"wp-image-790\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5-1024x432.png 1024w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5-300x127.png 300w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5-768x324.png 768w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5-624x263.png 624w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-5.png 1341w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Once we have the XML in the proper format we can put it back in the AD object:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-6.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"451\" height=\"498\" src=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-6.png\" alt=\"\" class=\"wp-image-791\" srcset=\"https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-6.png 451w, https:\/\/blog.markdepalma.com\/wp-content\/uploads\/2021\/09\/image-6-272x300.png 272w\" sizes=\"auto, (max-width: 451px) 100vw, 451px\" \/><\/a><\/figure>\n\n\n\n<p>Now that we&#8217;ve updated the AD object we can verify everything looks good by checking Exchange again (<strong>AppOnlyPermissions<\/strong> should have the same values as <strong>ActAsPermissions<\/strong>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Get-PartnerApplication | Where {$_.Name -like '*graph*'} | select *permissions* | fl\r\n\r\n\r\nAppOnlyPermissions : {Mail.Read, Mail.Write, Mail.Send, Calendars.Read...}\r\nActAsPermissions   : {Mail.Read, Mail.Write, Mail.Send, Calendars.Read...}<\/pre>\n\n\n\n<p>At this point you should be able to access on-prem Exchange resources using the supported Graph API functions with Application Permissions.<\/p>\n\n\n\n<p><strong>NOTE: One limitation of this is that <a href=\"https:\/\/docs.microsoft.com\/en-us\/graph\/auth-limit-mailbox-access\" target=\"_blank\" rel=\"noreferrer noopener\">application access policies<\/a> (set in EXO) <em>DO NOT<\/em> apply and are ignored when accessing an on-prem mailbox.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We recently came across an application that uses Graph API and we wanted to start using it for some our on-prem mailboxes. Hybrid Graph API only supports delegated authentication flows and not application authentication flows. Just because something isn&#8217;t &#8220;supported&#8221; doesn&#8217;t mean you can&#8217;t make it work! There are two things that we&#8217;ll need to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[64,69,99,65],"tags":[24,35,186,45,185,106],"class_list":["post-782","post","type-post","status-publish","format-standard","hentry","category-active-directory","category-exchange","category-o365","category-security","tag-active-directory","tag-api","tag-client-credentials","tag-exchange","tag-graph","tag-hybrid"],"_links":{"self":[{"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/posts\/782","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=782"}],"version-history":[{"count":11,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/posts\/782\/revisions"}],"predecessor-version":[{"id":800,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=\/wp\/v2\/posts\/782\/revisions\/800"}],"wp:attachment":[{"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=782"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=782"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.markdepalma.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=782"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}