{"id":560,"date":"2024-03-04T13:22:30","date_gmt":"2024-03-04T12:22:30","guid":{"rendered":"https:\/\/sparrow365.de\/?p=560"},"modified":"2024-11-04T20:20:51","modified_gmt":"2024-11-04T19:20:51","slug":"you-probably-dont-need-application-readwrite-all","status":"publish","type":"post","link":"https:\/\/sparrow365.de\/index.php\/en\/2024\/03\/04\/you-probably-dont-need-application-readwrite-all\/","title":{"rendered":"You (probably) don&#8217;t need Application.ReadWrite.All"},"content":{"rendered":"<p>When Microsoft <a href=\"https:\/\/msrc.microsoft.com\/blog\/2024\/01\/microsoft-actions-following-attack-by-nation-state-actor-midnight-blizzard\/\">first disclosed<\/a> the <strong>January Midnight Blizzard<\/strong> attack and posted their subsequent <a href=\"https:\/\/www.microsoft.com\/en-us\/security\/blog\/2024\/01\/25\/midnight-blizzard-guidance-for-responders-on-nation-state-attack\/\">deeper analysis<\/a> I followed the resulting content with great interest &#8211; <strong>risks posed by Enterprise Applications<\/strong> are a topic near and dear to me. <\/p>\n<blockquote>\n<p><em>I will try to keep this article standalone, but it might be a good idea to skim the Articles before continuing<\/em><\/p>\n<\/blockquote>\n<p>If you use Microsoft 365 to a reasonable level, you <strong><em>will<\/em><\/strong> have applications with a large scope of permissions <strong>in your Tenant<\/strong> (think Backup Solutions, Script Automations, etc.) &#8211; which is why you should treat the Entra ID Role <em>&quot;(Cloud) App Administrator&quot;<\/em> <strong>like a Global Administrator<\/strong>. By setting Credentials for the System Identity that holds the applications&#8216; permissions, they can connect to the associated APIs in its name and use privileges you might never have granted the Users directly. The <strong>same applies<\/strong> to the application-level Graph API role &quot;<strong>Application.ReadWrite.All<\/strong>&quot;.<\/p>\n<p>Since I don&#8217;t have anything to add to the main Points of Interest for the breach, <a href=\"https:\/\/jeffreyappel.nl\/pivot-via-oauth-applications-across-tenants-and-what-to-for-protection-with-microsoft-technology-midnight-blizzard\/\">lateral movement between Tenants<\/a> through enterprise Applications and how to correctly <a href=\"https:\/\/janbakker.tech\/a-love-story-about-role-based-access-control-for-applications-in-exchange-online-managed-identities-entra-id-admin-units-and-graph-api\/\">grant API permissions in Exchange Online<\/a>, I won&#8217;t be revisiting those topics. However, there is one area where I would like to see more Information &#8211; once <em>discovered in your Tenant<\/em>, it is sometimes not easy to find <strong>how to avoid<\/strong> or <strong>get rid of highly privileged API Roles.<\/strong> One such Example is <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/permissions-reference#applicationreadwriteall\"><strong>Application.ReadWrite.All<\/strong><\/a>.<\/p>\n<p>The whole Midnight Blizzard attack chain might have started directly with an App Owner of the Multi-Tenant App, but it could easily have been an application in the Test Tenant with this Permission, through which the Attacker moved to the Multi-Tenant App (Microsoft is not entirely clear on this).<\/p>\n<p>So, let&#8217;s take a look at some use cases where the <strong>first reflex<\/strong> might be to use <strong>&quot;Application.ReadWrite.All&quot;, but there are better solutions<\/strong>:<\/p>\n<blockquote>\n<p>I will be using PowerShell in my demos, but since Graph is a REST API, examples can be transferred to any Programming Language with support for HTTP requests<br \/>\n<em>I hold these truths to be self evident: Delegated Permissions are preferable over Application Permissions, and if you only need Read permissions you don&#8217;t use a ReadWrite scope<\/em><\/p>\n<\/blockquote>\n<p><br class=\"\"><\/p>\n<h2>General Configuration Management<\/h2>\n<p>To start out, in the vast majority of cases, we do not want to manage <strong>all<\/strong> applications in Tenant, but only a specific set. Let&#8217;s begin with an application wanting to manage its own configuration.<\/p>\n<blockquote>\n<p>Remember: In the Graph API <em>App Registrations<\/em> are on the <strong>application<\/strong> Endpoint, an <em>Enterprise app<\/em> is a <strong>servicePrincipal<\/strong> &#8211; <a href=\"https:\/\/www.shankuehn.io\/post\/app-registration-vs-enterprise-applications\"><em>Quick summary of the difference<\/em><\/a><br \/>\nWhen used too often I might refer to App Registrations as &quot;<strong>AppRegs<\/strong>&quot;, and Enterprise Apps as &quot;<strong>EApps<\/strong>&quot; <\/p>\n<\/blockquote>\n<h3>First Attempt<\/h3>\n<p>If we take a look at the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/application-update?view=graph-rest-1.0&amp;tabs=http#permissions\">Graph API documentation<\/a> for managing App Registrations, we can already see a potential Option (the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/serviceprincipal-update?view=graph-rest-1.0&amp;tabs=http#permissions\">same goes for Enterprise Apps<\/a>): <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/4_ApplicationPATCHPermissions.png\" alt=\"DocumentedLeastPrivileges\" \/><\/p>\n<p>So, we add the Scope to our App Registration, Grant the Permissions on the Enterprise App and are done, right?  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/5_AppPermissions.png\" alt=\"activeScopes\" \/><\/p>\n<p>Well, now that I have the scope in my Graph Session, I try to change my EApp to require a User to be assigned before they can log in:<br \/>\n<code>Invoke-MgGraphRequest &quot;PATCH&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals(appId=&#039;$($graphConfig.clientID)&#039;)&quot; -Body @{ appRoleAssignmentRequired = $true }<\/code> <\/p>\n<p><strong>And promptly get denied:<\/strong><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/3_PatchYourself.png\" alt=\"ErrorMessageSelfPatch\" \/><\/p>\n<p><br class=\"\"><\/p>\n<h3>Adding Ownership<\/h3>\n<p>This is logical if we think about it. We just gave the Enterprise App permission to manage applications <strong>that it Owns<\/strong>, but we <strong>don&#8217;t own anything<\/strong> <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/enterprise-apps\/overview-assign-app-owners\"><em>(Click here for Microsofts Overview of application ownership)<\/em><\/a>. So how do we fix that? At time of writing (Feb. 2024), the Entra Portal does not offer EApps when we try to add an Owner to an Enterprise App or an App Registration.    <\/p>\n<p>However, if we authenticate against the Graph API with the <strong><em>delegated<\/em><\/strong> Scope &quot;Application.ReadWrite.All&quot; as a user with <strong>at least Application Administrator<\/strong> (or Owner), we can add the necessary ownership &#8211; an Object can even own itself.<\/p>\n<blockquote>\n<p>Remember &#8211; Even though credentials are configured on the App Registration, <strong>the Enterprise App \/ service Principal holds all the Permissions in a Tenant<\/strong><\/p>\n<p>See also the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/serviceprincipal-post-owners?view=graph-rest-1.0&amp;tabs=http\">Microsoft Documentation of Adding Owners to Enterprise Apps<\/a><\/p>\n<\/blockquote>\n<pre><code class=\"language-powershell\"># Fetch the Object ID of our EApp by App \/ Client ID\n$enterpriseAppID    = ( Invoke-MgGraphRequest &quot;GET&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals(appId=&#039;$($graphConfig.clientID)&#039;)?select=id&quot; ).id\n\n# Add the EApp as an Owner to itself\n$params = @{ &quot;@odata.id&quot; = &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals\/$enterpriseAppID&quot; }\nInvoke-MgGraphRequest &quot;POST&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals\/$enterpriseAppID\/owners\/`$ref&quot; -Body $params<\/code><\/pre>\n<p><br class=\"\"><\/p>\n<p>So let&#8217;s try again <em>(We don&#8217;t get a response on successful execution so I won&#8217;t show the command line)<\/em>:<br \/>\n<code>Invoke-MgGraphRequest &quot;PATCH&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals(appId=&#039;$($graphConfig.clientID)&#039;)&quot; -Body @{ appRoleAssignmentRequired = $true }<\/code><\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/6_UpdateAppRegSuccess.png\" alt=\"alt\" \/><\/p>\n<p><strong>Success! And we can&#8217;t take over the entire Tenant from here, since we only control one Application<\/strong> \ud83e\udd73<\/p>\n<p>Funnily enough, even though we can&#8217;t add Enterprise Apps as Owners through the UI, once we added them, they are visible:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/2_DisplayedOwners.png\" alt=\"PortalOwnerView\" \/><\/p>\n<p><br class=\"\"><\/p>\n<p>If we need the ability to change the properties of our App Registration, we can add Ownership rights like this:<\/p>\n<blockquote>\n<p>In this example I am still using the App \/ Client ID of the EApp I am logged in as, replace as needed<\/p>\n<p>See also the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/application-post-owners?view=graph-rest-1.0&amp;tabs=http\">Microsoft Documentation of Adding Owners to App Registrations<\/a><\/p>\n<\/blockquote>\n<pre><code class=\"language-powershell\"># Fetch the ID of The EApp that we want to use for Management\n$enterpriseAppID    = (Invoke-MgGraphRequest &quot;GET&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals(appId=&#039;$($graphConfig.clientID)&#039;)?select=id&quot;).id\n$appRegistrationID  = (Invoke-MgGraphRequest &quot;GET&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/applications(appId=&#039;$($graphConfig.clientID)&#039;)?select=id&quot;).id\n\n# We add our EApp as the Owner of the AppReg \n$params = @{ &quot;@odata.id&quot; = &quot;https:\/\/graph.microsoft.com\/v1.0\/servicePrincipals\/$enterpriseAppID&quot; }\nInvoke-MgGraphRequest &quot;POST&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/applications\/$appRegistrationID\/owners\/`$ref&quot; -Body $params<\/code><\/pre>\n<p><br class=\"\"><\/p>\n<p>Now I should be able to manage the App Registration as well, so let&#8217;s try to add a redirect URI for SSO: <\/p>\n<pre><code class=\"language-powershell\">$params = @{ web = @{ redirectUris = @(&quot;https:\/\/demo.com&quot;) } }\nInvoke-MgGraphRequest &quot;PATCH&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/applications(appId=&#039;$($graphConfig.clientID)&#039;)&quot; -Body $params<\/code><\/pre>\n<p>And again we are successful:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/1_SuccessfullPatchOwnAppRegistration.png\" alt=\"appRegEditSuccess\" \/><\/p>\n<p><br class=\"\"><\/p>\n<h2>Application Credential Management<\/h2>\n<p>Probably one of the most common requests in application management is to <strong>self-manage credentials<\/strong>. The consistent Expiry of Secrets and Certificates is either in need of close monitoring or, preferably, automation.<\/p>\n<p>With &quot;<strong>Application.ReadWrite.OwnedBy<\/strong>&quot;, and our Enterprise App already having ownership of the App Registration from the last chapter, we can update Credentials &#8211; since they are just another property.<\/p>\n<h3>Secrets<\/h3>\n<blockquote>\n<p>See also the <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/application-update?view=graph-rest-1.0&amp;tabs=http\">Microsoft Documentation of Updating App Registrations<\/a><\/p>\n<\/blockquote>\n<pre><code class=\"language-powershell\">$appRegistrationID  = (Invoke-MgGraphRequest &quot;GET&quot; &quot;https:\/\/graph.microsoft.com\/v1.0\/applications(appId=&#039;$($graphConfig.clientID)&#039;)?select=id&quot;).id\n$params = @{\n    passwordCredential = @{\n        displayName = &quot;Secret$(get-date -f &quot;ddMMyy&quot;)&quot;\n    }\n}\n# Depending on where you need the secret, it is probably a good idea to put it there as quickly as possible ;) \n$response = Invoke-MgGraphRequest POST &quot;https:\/\/graph.microsoft.com\/v1.0\/applications\/$appRegistrationID\/addPassword&quot; -body $params<\/code><\/pre>\n<blockquote>\n<p><em>If I actually have to use secrets like this I prefer only storing them in secure strings, since they are better protected in memory:<\/em><br \/>\n<code><code>$secret = ConvertTo-SecureString $(Invoke-MgGraphRequest POST &quot;https:\/\/graph.microsoft.com\/v1.0\/applications\/$appRegistrationID\/addPassword&quot; -body $params).secretText -AsPlainText -Force<\/code><\/code><\/p>\n<\/blockquote>\n<p>In our Response we get the secret as secretText, along with some metadata (remember to store it somewhere, or it is gone forever):<br \/>\n<img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/7_SecretMetadata.png\" alt=\"secretMetadata\" \/><\/p>\n<p>We can also see the Secret in the UI (just not the Value):<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/8_SecretUI-e1709159393121.png\" alt=\"secretUI\" \/><\/p>\n<p><br class=\"\"><\/p>\n<h3>Keys \/ Certificates<\/h3>\n<p>However, I am sure <strong>noone needs secrets<\/strong> anymore. They are just so much <strong>worse than Asymmetric Authentication Methods<\/strong>, so obviously all Applications have <strong>moved to Certificates<\/strong> for Authentication right? <strong><em>RIGHT?<\/em><\/strong> A man can dream&#8230;<\/p>\n<p><a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/api\/application-addkey?view=graph-rest-1.0&amp;tabs=http#permissions\">In theory we could do manage Certificates <strong>even without<\/strong> &quot;<em>Application.ReadWrite.OwnedBy<\/em>&quot;<\/a> Permissions, but I was <a href=\"https:\/\/learn.microsoft.com\/en-us\/answers\/questions\/587303\/access-token-missing-or-malformed-when-doing-addke\">unable to get it to work<\/a> in PowerShell &#8211; I may revisit it later or would very much appreciate a pointer to a working implementation in the <a href=\"https:\/\/learn.microsoft.com\/en-us\/answers\/questions\/587303\/access-token-missing-or-malformed-when-doing-addke\">open Q&amp;A question<\/a>&#8230;<\/p>\n<p>With me being unable to demonstrate the <em>really cool<\/em> solution (for now), I don&#8217;t really have much to add to the <a href=\"[https:\/\/learn.microsoft.com\/en-us\/graph\/applications-how-to-add-certificate?tabs=powershell]\">Microsoft Documenation<\/a>. I do use the Value from the Certificate Store though:<\/p>\n<blockquote>\n<p>Keep in mind that this command <strong>REPLACES ALL CURRENTLY CONFIGURED CERTIFICATES<\/strong> on the enterprise application<\/p>\n<\/blockquote>\n<pre><code class=\"language-powershell\">$Certificate = Get-Item &quot;Cert:\\CurrentUser\\My\\$($graphConfig.newThumb)&quot; -ErrorAction Stop\n$params = @{\n    keyCredentials = @(\n        @{\n            type = &quot;AsymmetricX509Cert&quot;\n            usage = &quot;Verify&quot;\n            key = [convert]::ToBase64String($Certificate.GetRawCertData())\n            displayName = &quot;CN=20240228&quot;\n        }\n    )\n}\nInvoke-MgGraphRequest PATCH &quot;https:\/\/graph.microsoft.com\/v1.0\/applications(appId=&#039;$($graphConfig.clientID)&#039;)&quot; -Body $params<\/code><\/pre>\n<p><br class=\"\"><\/p>\n<h2>Scaling<\/h2>\n<p>So, we now have a good grasp of how we can manage single applications. But how do <strong>expand our Scope?<\/strong> There are usecases where we want to hold control over many Enterprise Apps \/ App Registrations <em>(I will shorten to<\/em> <strong>&quot;Apps&quot;<\/strong> <em>to refer to both from here on out)<\/em>. <\/p>\n<p>Think Infrastructure as Code Solutions like Terraform, or maybe we have a backup system that wants to circumvent <a href=\"[https:\/\/learn.microsoft.com\/en-us\/graph\/throttling-limits]\">Graph API rate limits<\/a> by creating <a href=\"https:\/\/documentation.commvault.com\/commvault\/v11_sp20\/article?p=105598.htm\">more EApps<\/a> <\/p>\n<p>So essentially we would need at least one &quot;Manager&quot; App and a bunch of &quot;Workers&quot;. The <em>annoying<\/em> solution would be to create a bunch of Apps in advance &#8211; and go through the <a href=\"#general-configuration-management\">base ownership assignment<\/a> afterwards. Not great, but thankfully it is much simpler &#8211; if we use &quot;<strong>Application.ReadWrite.OwnedBy<\/strong>&quot; on our &quot;Head&quot; Application, we can then use it to <strong>create Apps as needed<\/strong>.<\/p>\n<blockquote>\n<p><em>We can also call the servicePrincipal Endpoint to create associated Enterprise Apps, but that just looks the same<\/em><\/p>\n<\/blockquote>\n<p><code>Invoke-MgGraphRequest POST &quot;https:\/\/graph.microsoft.com\/v1.0\/applications&quot; -body @{ displayName = &quot;CreatedByApp&quot; }<\/code><\/p>\n<p>The executing Enterprise App is <strong>automatically added as the Owner<\/strong> of the new App:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/sparrow365.de\/wp-content\/uploads\/2024\/02\/10createNewApps.png\" alt=\"newAppReg\" \/><\/p>\n<p><br class=\"\"><\/p>\n<p>However, keeping track of all our ownership relations will be challenging. The solutions I know as currently available are <strong>building an automation<\/strong> based on <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/fundamentals\/custom-security-attributes-overview\">Custom Security Attributes<\/a> or <strong>creating a tracking system<\/strong> in <a href=\"https:\/\/learn.microsoft.com\/en-us\/graph\/extensibility-overview?tabs=http#directory-microsoft-entra-id-extensions\">directory extensions<\/a>. Either way, these are not great options &#8211; so are we doomed to either give <strong>far too broad permissions<\/strong> or try to keep track of a potentially <strong>complex web of ownership relations<\/strong>?<\/p>\n<p><br class=\"\"><\/p>\n<h2>The &quot;Best&quot; Option<\/h2>\n<p>If we <strong>truly<\/strong> want to go for &quot;least privilege&quot;, Graph API Scopes are not the way. At their core, Apps are Entra ID Objects, making <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/role-based-access-control\/custom-enterprise-app-permissions\">custom roles<\/a> a significantly more granular option for permissions management. &quot;<strong>Application.ReadWrite.OwnedBy<\/strong>&quot; just happens to be almost a <strong>drop in replacement<\/strong> for the commonly used &quot;<strong>Application.ReadWrite.All<\/strong>&quot;. <\/p>\n<blockquote>\n<p>OAuth scopes have the advantage of being easily transferrable between Tenants &#8211; when creating an Application only for your Tenant this is not really a fair argument and you better really REALLY trust the developer to give these permissions to a multi-tenant App&#8230;<\/p>\n<\/blockquote>\n<p>Once we look at the Options available in Entra ID, there would be one painfully obvious solution: For Users, Groups and Devices we can already create <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/role-based-access-control\/administrative-units\"><strong>Administrative Units<\/strong><\/a>. These allow scoping Built-In and Custom Roles only to a <strong>subset of Objects<\/strong> in a directory, including the creation of new objects within its&#8216; scope.<br \/>\nThis would result in an easily <strong>scalable and auditable collection<\/strong> of Apps.<br \/>\nAlas, using AUs to manage Apps is currently (March 2024) <strong>not supported<\/strong> by Microsoft&#8230;<\/p>\n<p><br class=\"\"><\/p>\n<h2>Conclusion<\/h2>\n<p>On your <a href=\"https:\/\/www.michev.info\/blog\/post\/5922\/reporting-on-entra-id-integrated-applications-service-principals-and-their-permissions\">next review of App Permissions<\/a>, ask developers if it would be possible to use <strong>less privileges<\/strong>. Remember, prioritizing <strong>safety is often secondary<\/strong> in the development process. Challenge the assertion &#8218;<em>we just need it<\/em>&#8218; by looking for the specific usecases that have to be covered &#8211; maybe there are solutions that have not been considered.<\/p>\n<p>On the other hand, even though I go into how we can and should replace <em>Application.ReadWrite.All<\/em>, this is not <em>always<\/em> a good idea. If there is a System that Owns 90% of Apps, the <strong>management Overhead<\/strong> usually does not justify the little added security.<br \/>\nAdditionally, if you find the option of Entra ID custom roles interesting, understanding which Entra ID Permissions are necessary for a given Graph operation <strong>is not easy<\/strong> &#8211; you have to be willing to take on some trial and error.<\/p>\n<p><br class=\"\"><\/p>\n<p>Did I miss a common usecase or you want to debate me why one might need <strong>Application.ReadWrite.All<\/strong>? I don&#8217;t want your email address, so please <a href=\"https:\/\/www.linkedin.com\/posts\/julian-sperling-4bba72228_you-probably-dont-need-applicationreadwriteall-activity-7170393660268773377-wlmL?utm_source=share&amp;utm_medium=member_desktop\">discuss on my associated LinkedIn Post<\/a>.<\/p>\n<p><br class=\"\"><\/p>\n<p>If you are interested in the things I do <a href=\"https:\/\/www.linkedin.com\/in\/julian-sperling-4bba72228\/\">follow me on LinkedIn<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When Microsoft first disclosed the January Midnight Blizzard attack and posted their subsequent deeper analysis I followed the resulting content with great interest &#8211; risks posed by Enterprise Applications are a topic near and dear to me. I will try to keep this article standalone, but it might be a good idea to skim the&#8230; &raquo; <a class=\"read-more-link\" href=\"https:\/\/sparrow365.de\/index.php\/en\/2024\/03\/04\/you-probably-dont-need-application-readwrite-all\/\">weiterlesen<\/a><\/p>\n","protected":false},"author":2,"featured_media":562,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[76,78],"tags":[80,82,236,232,230,84,165,234,238,88,90,96,98,228,100,169,171,240],"class_list":["post-560","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-me-id-en","category-powershell-en","tag-aad-en","tag-aad-connect-en","tag-administrative-units","tag-application-readwrite-all","tag-application-readwrite-ownedby","tag-azure-ad-en","tag-best-practices-en","tag-custom-roles","tag-enterprise-app-ownership","tag-entra-en","tag-entra-id-en","tag-graph-en","tag-graph-api-en","tag-least-privilege","tag-microsoft-graph-en","tag-minimize-access-en","tag-overprivilege-en","tag-security"],"_links":{"self":[{"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/posts\/560","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/comments?post=560"}],"version-history":[{"count":8,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/posts\/560\/revisions"}],"predecessor-version":[{"id":578,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/posts\/560\/revisions\/578"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/media\/562"}],"wp:attachment":[{"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/media?parent=560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/categories?post=560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sparrow365.de\/index.php\/wp-json\/wp\/v2\/tags?post=560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}