{"id":2651,"date":"2014-02-16T14:54:35","date_gmt":"2014-02-16T21:54:35","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/?p=2651"},"modified":"2014-02-16T17:46:39","modified_gmt":"2014-02-17T00:46:39","slug":"a-sample-windows-phone-8-app-getting-tokens-from-windows-azure-ad-and-adfs","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2014\/02\/16\/a-sample-windows-phone-8-app-getting-tokens-from-windows-azure-ad-and-adfs\/","title":{"rendered":"A Sample Windows Phone 8 App Getting Tokens from Windows Azure AD and ADFS"},"content":{"rendered":"<p>Few months ago I wrote a <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/04\/29\/fun-with-windows-azure-ad-calling-rest-services-from-a-windows-phone-8-app\/\">quick post<\/a> to demonstrate how to get a token from Windows Azure AD in a Windows Phone 8 application. I am happy to report that many people have been successfully using that post as a starting point! However, few others didn\u2019t manage on their own and asked for help. Given that 1:1 help is unfeasible given my narrow bandwidth, I decided to write an even simpler sample app and push it on GitHub: you can find it <a href=\"https:\/\/github.com\/vibronet\/AAD_Client_WP8\">here<\/a>. <br \/>In fact, I found it handy to have such app on my device! Hence, I am also publishing it on the Windows Phone Store <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none\" alt=\"Smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wlEmoticon-smile1.png\">. <br \/>This post is going to provide the help page for the app, with basic usage instructions. <br \/>Also: the code in the <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/04\/29\/fun-with-windows-azure-ad-calling-rest-services-from-a-windows-phone-8-app\/\">original post<\/a> didn\u2019t take advantage of the improvements we introduced in the meanwhile (ADFS support for OAuth2, portable HttpClient package for Windows Phone, id_token\u2026) hence I took the chance to freshen up those parts as well \u2013 I\u2019ll briefly discuss the code authentication logic in the appendix of the post. <\/p>\n<p><strong><u><font color=\"#ff0000\">IMPORTANT<\/font><\/u><\/strong>: This is my personal blog. This app does not represent any best practice.I am not committing to support this sample in any shape or form. I am not a Windows Phone expert, and I did not write this sample in official capacity. <\/p>\n<h2>How to Use the App<\/h2>\n<p>The application provides you a simple interface you can use to request an access token from a Windows Azure AD tenant or an ADFS W2012 R2 instance. <br \/>You can use this app to simulate requests from your own client applications, all you need to do is entering the values describing your client app and the resource you are targeting.<\/p>\n<h3>Basic Usage<\/h3>\n<p>&nbsp;<\/p>\n<p>The main screen appears as in the following:<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/First-screen.png\"><img loading=\"lazy\" decoding=\"async\" title=\"First screen\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"First screen\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/First-screen_thumb.png\" width=\"288\" height=\"480\"><\/a><\/p>\n<p>You can use the text boxes to enter all the coordinates which define the request you want to submit, and specifically:<\/p>\n<ul>\n<li><strong>Authority<\/strong>: the Windows Azure AD tenant or ADFS instance managing the user account you want to use<\/li>\n<li><strong>ClientID<\/strong>: the identifier of your client application, as configured in the authority<\/li>\n<li><strong>Resource<\/strong>: the resource identifier of the web api you want&nbsp; a token for. Note, this app does not actually use the token with the resource \u2013 it just acquires it. See below for ways in which you can use that token outside of the app<\/li>\n<li><strong>RedirectUri<\/strong>: the redirect Uri of your client application, as configured in the authority<\/li>\n<\/ul>\n<p>To make things easier, the app comes preconfigured with the coordinates for testing the Windows Azure Cmdlets accessing the RDFE API. That, plus the use of the common tenant, allow you to see the app in action right away: you can use any account from your subscription.<\/p>\n<p>Once you are satisfied with the values you entered (or with the defaults) click \u201cGet Token&gt;&gt;\u201d.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/connect.png\"><img loading=\"lazy\" decoding=\"async\" title=\"connect\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"connect\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/connect_thumb.png\" width=\"288\" height=\"480\"><\/a><\/p>\n<p>The next screen holds the familiar credential prompt of Windows Azure AD (or ADFS if that\u2019s what you pointed to), as shown through a browser control. Enter the credentials of the account you want to use and hit sign in.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/token.png\"><img loading=\"lazy\" decoding=\"async\" title=\"token\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"token\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/token_thumb.png\" width=\"288\" height=\"480\"><\/a><\/p>\n<p>If everything goes well, you\u2019ll see the screen above. <br \/>The access and refresh tokens are presented in their base64\u2019ed form: you can select the text, copy and paste it wherever you want.<\/p>\n<p>The id token, when present (ADFS does not issue it), is shown in human-readable form so that you can get an idea of whether the token you got is in line with what you were expecting or not.<\/p>\n<h3>Errors<\/h3>\n<p>The error management logic is barely there (remember the disclaimer!).<\/p>\n<p>When something does not go according to plan, you\u2019ll typically be unceremoniously presented with the dump of what we got back from the service.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/error.png\"><img loading=\"lazy\" decoding=\"async\" title=\"error\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"error\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/error_thumb.png\" width=\"288\" height=\"480\"><\/a><\/p>\n<p>After dismissing the dialog, you are brought back to the main screen so that you can correct the issue.<\/p>\n<h3>Copy to Clipboard<\/h3>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/clip.png\"><img loading=\"lazy\" decoding=\"async\" title=\"clip\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"clip\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/clip_thumb.png\" width=\"288\" height=\"480\"><\/a><\/p>\n<p>You can copy to the clipboard the entire content of the screen. Just touch the copy button on the app bar and all the values on all the visible fields will be saved in a JSON file and copied. That is useful when you want to grab one of the tokens and inject it in some sample code which hits the web API you want to target \u2013 I do it all the time for the Graph.&nbsp; <\/p>\n<p>Note: you can also copy values of authority, clientid, etc that you plan to use frequently, so that you don\u2019t have to type them in all the time. Just hit the copy button while on the first screen, and you\u2019ll get all the values saved in the clipboard in the format below:<\/p>\n<p><font face=\"Consolas\">{ &#8220;authority&#8221; : &#8220;https:\/\/login.windows.net\/treyresearch1.onmicrosoft.com&#8221;,&#8221;clientid&#8221; : &#8220;4a491cff-73a9-4a45-b274-b5836a723b14&#8243;,&#8221;redirecturi&#8221; : &#8220;http:\/\/whatevah&#8221;,&#8221;resource&#8221; : <\/font><a href=\"http:\/\/localhost:8643\/\"><font face=\"Consolas\">http:\/\/localhost:8643\/<\/font><\/a><font face=\"Consolas\">}<\/font><\/p>\n<h3>Feeding Values Via File<\/h3>\n<p>Typing long values on the phone is a chore, and typing a GUID is torture. I thought how to make it easier to enter the initial coordinates, and remembered a great feature of Windows Phone apps: you can associate a file type to your app, so that whenever the user tries to open that file your app gets launched. Hence, I defined an easy file format (the same JSON dump you get when you copy values to the clipboard), registered one improbable extension (.tknrq), defined a default icon for the file format and voila\u2019!<br \/>To demonstrate the process, I saved a couple of such files (pointing to one AAD and one ADFS), sent them as attachment to myself, and tried to open them from Outlook on the phone.<\/p>\n<p>Here there\u2019s the email with the attachment, note that given that I have the app installed the token format is recognized.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0001.png\"><img loading=\"lazy\" decoding=\"async\" title=\"wp_ss_20140216_0001\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"wp_ss_20140216_0001\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0001_thumb.png\" width=\"270\" height=\"480\"><\/a><\/p>\n<p>Clicking on contoso100_ADFS.tknrq we get transported to the app, which gets initialized with the corresponding values:<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0002.png\"><img loading=\"lazy\" decoding=\"async\" title=\"wp_ss_20140216_0002\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"wp_ss_20140216_0002\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0002_thumb.png\" width=\"270\" height=\"480\"><\/a><\/p>\n<p>Just to be sure, clicking on Get Token results in the ADFS authentication page popping up.<\/p>\n<p><a href=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0003.png\"><img loading=\"lazy\" decoding=\"async\" title=\"wp_ss_20140216_0003\" style=\"border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px\" border=\"0\" alt=\"wp_ss_20140216_0003\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wp_ss_20140216_0003_thumb.png\" width=\"270\" height=\"480\"><\/a><\/p>\n<p>It\u2019s that simple! <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none\" alt=\"Smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wlEmoticon-smile1.png\"><\/p>\n<h2>The Token Acquisition Logic<\/h2>\n<p>As promised, here there\u2019s some commentary on the token acquisition logic.<br \/>The principles remain the same ones I covered in the <a href=\"https:\/\/www.cloudidentity.com\/blog\/2013\/04\/29\/fun-with-windows-azure-ad-calling-rest-services-from-a-windows-phone-8-app\/\">old post<\/a>, hence I won\u2019t go as deep.<\/p>\n<p>Al the interesting stuff takes place in <strong>SignInPage.xaml.cs<\/strong>. That\u2019s the place where I host the browser control for orchestrating the authorization code acquisition, and the follow up call to the token endpoint for redeeming it for actual tokens. Thanks to the platform improvements occurred in the last few months, that logic now boils down to just three methods.<\/p>\n<pre class=\"csharpcode\"><span class=\"rem\">\/\/ build the URL of the Authorization endpoint from the app state<\/span>\r\n<span class=\"rem\">\/\/ navigate to it via browser control<\/span>\r\n<span class=\"kwrd\">protected<\/span> <span class=\"kwrd\">override<\/span> <span class=\"kwrd\">void<\/span> OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)\r\n{\r\n    <span class=\"kwrd\">base<\/span>.OnNavigatedTo(e);\r\n\r\n    <span class=\"kwrd\">string<\/span> authURL = <span class=\"kwrd\">string<\/span>.Format(\r\n        <span class=\"str\">\"{0}\/oauth2\/authorize?response_type=code&amp;resource={1}&amp;client_id={2}&amp;redirect_uri={3}\"<\/span>,\r\n        app.Authority,\r\n        app.Resource,\r\n        app.ClientID,\r\n        app.RedirectUri);\r\n    <span class=\"rem\">\/\/navigate to it<\/span>\r\n    myBrowser.Navigate(<span class=\"kwrd\">new<\/span> Uri(authURL));\r\n}\r\n<\/pre>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p>OnNavigatedTo retrieves the request parameters from the App properties and crafts the authorization URL. Whereas during the original post this flow was only possible with Windows Azure AD, now it\u2019s possible with ADFS too; hence the tenantID parameter was eliminated in favor of a more comprehensive authority, which includes the hostname and can be used to represent both on-premises and cloud endpoints.<br \/>As soon as the URL is ready, the method navigates straight to it.<\/p>\n<pre class=\"csharpcode\"><span class=\"rem\">\/\/ watch for the redirect URI, once you see it <\/span>\r\n<span class=\"rem\">\/\/    - stop navigation<\/span>\r\n<span class=\"rem\">\/\/    - retrieve the authorization code<\/span>\r\n<span class=\"rem\">\/\/    - hit the Token endpoint<\/span>\r\n<span class=\"rem\">\/\/    - put the result back in the app state and go back to main<\/span>\r\n<span class=\"kwrd\">private<\/span> async <span class=\"kwrd\">void<\/span> Navigating(<span class=\"kwrd\">object<\/span> sender, NavigatingEventArgs e)\r\n{\r\n    <span class=\"kwrd\">string<\/span> returnURL = e.Uri.ToString();\r\n    <span class=\"kwrd\">if<\/span> (returnURL.StartsWith(app.RedirectUri))\r\n    {\r\n        <span class=\"kwrd\">string<\/span> code = e.Uri.Query.Remove(0, 6);\r\n        e.Cancel = <span class=\"kwrd\">true<\/span>;\r\n        myBrowser.Visibility = System.Windows.Visibility.Collapsed;\r\n\r\n        app.Response = await RequestToken(code);\r\n        \r\n        Dispatcher.BeginInvoke(() =&gt;\r\n        {\r\n            NavigationService.GoBack();\r\n        });\r\n    }\r\n}\r\n<\/pre>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p>The Navigating event is used to watch out for requests for the RedirectUri, which signal that the code negotiation concluded. The parsing logic could be more robust, but so far it worked.<br \/>The code is fed to the RequestToken, which will redeem it. Note that the call will take place even if the code acquisition failed \u2013 some error detection at this point might save some cycles, but we\u2019ll trap it anyway afterwards.<\/p>\n<p>Once the call to RequestToken concluded, we go back to the page that called us. That page will be responsible to interpret the results saved in app.Response.<\/p>\n<pre class=\"csharpcode\"><span class=\"rem\">\/\/ construct the request for the Token endpoint<\/span>\r\n<span class=\"rem\">\/\/ hit the endpoint and return the results<\/span>\r\n<span class=\"kwrd\">private<\/span> async Task&lt;<span class=\"kwrd\">string<\/span>&gt; RequestToken(<span class=\"kwrd\">string<\/span> code)\r\n{\r\n    HttpClient client = <span class=\"kwrd\">new<\/span> HttpClient();\r\n    HttpRequestMessage request = <span class=\"kwrd\">new<\/span> HttpRequestMessage(HttpMethod.Post, <span class=\"kwrd\">string<\/span>.Format(<span class=\"str\">\"{0}\/oauth2\/token\"<\/span>, app.Authority));\r\n    <span class=\"kwrd\">string<\/span> tokenreq = <span class=\"kwrd\">string<\/span>.Format(\r\n            <span class=\"str\">\"grant_type=authorization_code&amp;code={0}&amp;client_id={1}&amp;redirect_uri={2}\"<\/span>,\r\n            code,\r\n            app.ClientID,\r\n            HttpUtility.UrlEncode(app.RedirectUri));\r\n    request.Content = <span class=\"kwrd\">new<\/span> StringContent(tokenreq, Encoding.UTF8, <span class=\"str\">\"application\/x-www-form-urlencoded\"<\/span>);\r\n    HttpResponseMessage response = await client.SendAsync(request);\r\n    <span class=\"kwrd\">string<\/span> responseString = await response.Content.ReadAsStringAsync();\r\n    <span class=\"kwrd\">return<\/span> responseString;\r\n}\r\n<\/pre>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p>RequestToken is far more compact than the original, thanks to the awesome <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Net.Http\">HttpClient PCL<\/a> now available on Windows Phone too.<\/p>\n<p>&nbsp;<\/p>\n<h2><\/h2>\n<h2>Wrap<\/h2>\n<p>Well, that was a fun Saturday night! <br \/>Windows Phone is an incredibly easy platform, I was able to do advanced stuff (like associating file formats and similar) in no time. And of course, hitting OAuth2 endpoints on AD is trivial \u2013 the token lifecycle less so, once you have it you have to keep it somewhere, refresh it at the right time etc etc but this should be a robust starting point. In fact, I am actually using the app on my own devices &amp; projects \u2013 it\u2019s a quick way of getting test tokens to quickly try things with APIs.<br \/>Please always remember the disclaimer <img decoding=\"async\" class=\"wlEmoticon wlEmoticon-smile\" style=\"border-top-style: none; border-left-style: none; border-bottom-style: none; border-right-style: none\" alt=\"Smile\" src=\"https:\/\/www.cloudidentity.com\/blog\/wp-content\/uploads\/2014\/02\/wlEmoticon-smile1.png\"> and have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Few months ago I wrote a quick post to demonstrate how to get a token from Windows Azure AD in a Windows Phone 8 application. I am happy to report that many people have been successfully using that post as a starting point! However, few others didn\u2019t manage on their own and asked&#8230;<\/p>\n","protected":false},"author":1,"featured_media":2636,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2651","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2651","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=2651"}],"version-history":[{"count":1,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2651\/revisions"}],"predecessor-version":[{"id":2652,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/2651\/revisions\/2652"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/2636"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=2651"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=2651"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=2651"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}