{"id":1183,"date":"2010-07-21T12:07:06","date_gmt":"2010-07-21T12:07:06","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/odatateam\/2010\/07\/21\/odata-and-authentication-part-7-forms-authentication\/"},"modified":"2024-02-16T14:55:00","modified_gmt":"2024-02-16T21:55:00","slug":"odata-and-authentication-part-7-forms-authentication","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/odata\/odata-and-authentication-part-7-forms-authentication\/","title":{"rendered":"OData and Authentication \u2013 Part 7 \u2013 Forms Authentication"},"content":{"rendered":"<p>Our goal in this post is to re-use the Forms Authentication already in a website to secure a new Data Service.<\/p>\n<p>To bootstrap this we need a website that uses Forms Auth.<\/p>\n<p>Turns out the <a href=\"https:\/\/mvcmusicstore.codeplex.com\/\">MVC Music Store Sample<\/a> is perfect for our purposes because:<\/p>\n<ul>\n<li>It uses Forms Authentication. For example when you purchase an album. <\/li>\n<li>It has a Entity Framework model that is clearly separated into two types of entities:      \n<ul>\n<li>Those that anyone should be able to browse (Albums, Artists, Genres). <\/li>\n<li>Those that are more sensitive (Orders, OrderDetails, Carts). <\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>The rest of this post assumes you\u2019ve downloaded and installed the MVC Music Store sample.<\/p>\n<h3><\/h3>\n<h4>Enabling Forms Authentication:<\/h4>\n<p>The MVC Music Store sample already has Forms Authentication enabled in the web.config like this:<\/p>\n<p><font face=\"Courier New\">&lt;authentication mode=&quot;Forms&quot;&gt;      <br \/>&#160; &lt;forms loginUrl=&quot;~\/Account\/LogOn&quot; timeout=&quot;2880&quot; \/&gt;       <br \/>&lt;\/authentication&gt;<\/font><\/p>\n<p>With this in place any services we add to this application will also be protected.<\/p>\n<h4>Adding a Music Data Service:<\/h4>\n<p>If you double click the StoreDB.edmx file inside the Models folder you\u2019ll see something like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/2438.MvcMusicStoreModel_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"MvcMusicStoreModel\" border=\"0\" alt=\"MvcMusicStoreModel\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/2438.MvcMusicStoreModel_thumb.png\" width=\"244\" height=\"166\" \/><\/a> <\/p>\n<p>This is want we want to expose, so the first step is to click \u2018Add New Item\u2019 and then select new WCF Data Service:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/6254.CreateMusicStoreService_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"CreateMusicStoreService\" border=\"0\" alt=\"CreateMusicStoreService\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/6254.CreateMusicStoreService_thumb.png\" width=\"244\" height=\"170\" \/><\/a> <\/p>\n<p>Next modify your MusicStoreService to look like this:<\/p>\n<p><font face=\"Courier New\">public class MusicStoreService : DataService&lt;MusicStoreEntities&gt;      <br \/>{       <br \/>&#160;&#160;&#160; \/\/ This method is called only once to initialize service-wide policies.       <br \/>&#160;&#160;&#160; public static void InitializeService(DataServiceConfiguration config)       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; config.SetEntitySetAccessRule(&quot;Carts&quot;, EntitySetRights.None);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; config.SetEntitySetAccessRule(&quot;OrderDetails&quot;, EntitySetRights.ReadSingle);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; config.SetEntitySetAccessRule(&quot;*&quot;, EntitySetRights.AllRead);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; config.SetEntitySetPageSize(&quot;*&quot;, 50);<\/font><font face=\"Courier New\">      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; config.DataServiceBehavior.MaxProtocolVersion =       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; DataServiceProtocolVersion.V2;       <br \/>&#160;&#160;&#160; }       <br \/>}<\/font><\/p>\n<p>The PageSize is there to enforce <a href=\"http:\/\/blogs.msdn.com\/b\/astoriateam\/archive\/2010\/02\/02\/server-paging-in-data-services.aspx\">Server Driven Paging<\/a>, which is an OData best practice, we don\u2019t like to show samples that skip this\u2026 \ud83d\ude42<\/p>\n<p>Then the three EntitySetAccessRules in turn:<\/p>\n<ul>\n<li>Hide the Carts entity set \u2013 our service shouldn\u2019t expose it. <\/li>\n<li>Allow OrderDetails to be retrieved by key, but not queried arbitrarily. <\/li>\n<li>Allow all other sets to be queried by not modified \u2013 in this case we want the service to be read-only. <\/li>\n<\/ul>\n<p>Next we need to secure our \u2018sensitive data\u2019, which means making sure only appropriate people can see Orders and OrderDetails, by adding two QueryInterceptors to our MusicStoreService:<\/p>\n<p><font face=\"Courier New\">[QueryInterceptor(&quot;Orders&quot;)]      <br \/>public Expression&lt;Func&lt;Order, bool&gt;&gt; OrdersFilter()       <br \/>{&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br \/>&#160;&#160;&#160; if (!HttpContext.Current.Request.IsAuthenticated)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (Order o) =&gt; false; <\/font><\/p>\n<p><font face=\"Courier New\">&#160;&#160;&#160; var username = HttpContext.Current.User.Identity.Name;      <br \/>&#160;&#160;&#160; if (username == &quot;Administrator&quot;)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (Order o) =&gt; true;       <br \/>&#160;&#160;&#160; else       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (Order o) =&gt; o.Username == username;       <br \/>} <\/font><\/p>\n<p><font face=\"Courier New\">[QueryInterceptor(&quot;OrderDetails&quot;)]      <br \/>public Expression&lt;Func&lt;OrderDetail, bool&gt;&gt; OrdersFilter()       <br \/>{       <br \/>&#160;&#160;&#160; if (!HttpContext.Current.Request.IsAuthenticated)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (OrderDetail od) =&gt; false; <\/font><\/p>\n<p><font face=\"Courier New\">&#160;&#160;&#160; var username = HttpContext.Current.User.Identity.Name;      <br \/>&#160;&#160;&#160; if (username == &quot;Administrator&quot;)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (OrderDetail od) =&gt; true;       <br \/>&#160;&#160;&#160; else       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return (OrderDetail od) =&gt; od.Order.Username == username;       <br \/>}<\/font><\/p>\n<p>These interceptors filter out all Orders and OrderDetails if the request is unauthenticated.<\/p>\n<p>They allow the administrator to see all Orders and OrderDetails, but everyone else can only see Orders \/ OrderDetails that they created.<\/p>\n<p>That\u2019s it &#8211; our service is ready to go. <\/p>\n<p><font color=\"#808080\"><strong>NOTE:<\/strong> if you have a read-write service and you want to authorize updates you need <\/font><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd744842.aspx\"><font color=\"#808080\">ChangeInterceptors<\/font><\/a><font color=\"#808080\">.<\/font><\/p>\n<h3>Trying it out in the Browser:<\/h3>\n<p>The easiest way to logon is to add something to your cart and buy it:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/4604.ShoppingCart_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"ShoppingCart\" border=\"0\" alt=\"ShoppingCart\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/4604.ShoppingCart_thumb.png\" width=\"244\" height=\"175\" \/><\/a> <\/p>\n<p>Which prompts you to logon or register:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/4201.LogonOrRegister_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"LogonOrRegister\" border=\"0\" alt=\"LogonOrRegister\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/4201.LogonOrRegister_thumb.png\" width=\"244\" height=\"175\" \/><\/a> <\/p>\n<p>The first time through you\u2019ll need to register, which will also log you on, and then once you are logged on you\u2019ll need to retry checking out.<\/p>\n<p>This has the added advantage of testing our security. Because at the end of the checkout process you will be logged in as the user you just registered, meaning if you browse to your Data Service\u2019s Orders feed you should see the order you just created:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/7762.OrdersAuthenticated_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"OrdersAuthenticated\" border=\"0\" alt=\"OrdersAuthenticated\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/7762.OrdersAuthenticated_thumb.png\" width=\"244\" height=\"175\" \/><\/a> <\/p>\n<p>If however you logoff, or restart the browser, and try again you\u2019ll see an empty feed like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/0830.OrdersUnauthenticated_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"OrdersUnauthenticated\" border=\"0\" alt=\"OrdersUnauthenticated\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/0830.OrdersUnauthenticated_thumb.png\" width=\"244\" height=\"175\" \/><\/a> <\/p>\n<\/p>\n<\/p>\n<p>Perfect. Our query interceptors are working as intended.<\/p>\n<p>This all works because Forms Authentication is essentially just a HttpModule, which sits under our Data Service, that relies on the browser (or client) passing around a cookie once it has logged on.<\/p>\n<p>By the time the request gets to the DataService the HttpContext.Current.Request.User is set. <\/p>\n<p>Which in turn means our query interceptors can enforce our custom Authorization logic.<\/p>\n<h3>Enabling Active Clients:<\/h3>\n<p>In authentication terms a browser is a passive client, that\u2019s because basically it does what it is told, a server can redirect it to a logon page which can redirect it back again if successful, it can tell it to include a cookie in each request and so on&#8230; <\/p>\n<p>Often however it is active clients \u2013 things like custom applications and generic data browsers \u2013 that want to access the OData Service.<\/p>\n<p>How do they authenticate?<\/p>\n<p>They could mimic the browser, by responding to redirects and programmatically posting the logon form to acquire the cookie. But no wants to re-implement html form handling just to logon.<\/p>\n<p>Thankfully there is a much easier way.<\/p>\n<p>You can enable an standard authentication endpoint, by adding this to your web.config:<\/p>\n<p><font face=\"Courier New\">&lt;system.web.extensions&gt;      <br \/>&#160; &lt;scripting&gt;       <br \/>&#160;&#160;&#160; &lt;webServices&gt;       <br \/>&#160;&#160;&#160;&#160;&#160; &lt;authenticationService enabled=&quot;true&quot; requireSSL=&quot;false&quot;\/&gt;       <br \/>&#160;&#160;&#160; &lt;\/webServices&gt;       <br \/>&#160; &lt;\/scripting&gt;       <br \/>&lt;\/system.web.extensions&gt;<\/font><\/p>\n<p>The endpoint (Authentication_JSON_AppService.axd) makes it much easier to logon programmatically.<\/p>\n<h3>Connecting from an Active Client:<\/h3>\n<p>Now that we\u2019ve enabled the authentication endpoint, lets see how we use it. Essentially for forms authentication to work the DataServiceContext must include a valid cookie with every request. <\/p>\n<p>A cookie is just a http header and, as we saw in <a href=\"http:\/\/blogs.msdn.com\/b\/astoriateam\/archive\/2010\/05\/24\/odata-and-authentication-part-3-clientside-hooks.aspx\">part 3<\/a>, it is very easy to add a custom header with every request.<\/p>\n<h4>Using Client Application Services:<\/h4>\n<p>But before we get down to setting cookies, in some scenarios there is an even easy way: using <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb384297.aspx\">Client Application Services<\/a>. These services are not available in the .NET Client Profile (or Silverlight) so you may need to change your Target Framework to use them:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/1016.ClientProfile_thumb_1.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"ClientProfile\" border=\"0\" alt=\"ClientProfile\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/1016.ClientProfile_thumb_1.png\" width=\"244\" height=\"170\" \/><\/a> <\/p>\n<p>Once you\u2019ve done that you enable Client Application Services like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/1030.ClientApplicationServices_thumb.png\"><img decoding=\"async\" style=\"border-right-width: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px\" title=\"ClientApplicationServices\" border=\"0\" alt=\"ClientApplicationServices\" src=\"https:\/\/devblogs.microsoft.com\/odatateam\/wp-content\/uploads\/sites\/23\/2010\/07\/1030.ClientApplicationServices_thumb.png\" width=\"244\" height=\"169\" \/><\/a> <\/p>\n<p><font color=\"#808080\"><strong>NOTE:<\/strong> the Authentication Services Location should be set to the root of the website that has Authentication Services enabled.<\/font><\/p>\n<p>Next you add a reference to System.Web to gain access to System.Web.Security.Membership.<\/p>\n<p>Once you\u2019ve done this you simply need to logon once:<\/p>\n<p><font face=\"Courier New\">System.Web.Security.Membership.ValidateUser(&quot;Alex&quot;, &quot;password&quot;);<\/font><\/p>\n<p>This logs on and stores the resulting cookie on the current thread.<\/p>\n<p>Next, assuming you already have a Service Reference to your Data Service \u2013 <a href=\"http:\/\/blogs.msdn.com\/b\/astoriateam\/archive\/2010\/01\/28\/getting-started-with-the-data-service-update-for-net-3-5-sp1-part-2.aspx\">see this to learn how<\/a> \u2013 you can extend your custom DataServiceContext, in our example called MusicStoreEntities, to automatically send the cookie with each request:<\/p>\n<p><font face=\"Courier New\">public partial class MusicStoreEntities      <br \/>{       <br \/>&#160;&#160;&#160; partial void OnContextCreated()       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.SendingRequest +=       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new EventHandler&lt;SendingRequestEventArgs&gt;(OnSendingRequest);&#160; <br \/>&#160;&#160;&#160; }       <br \/>&#160;&#160;&#160; void OnSendingRequest(object sender, SendingRequestEventArgs e)       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/font><font face=\"Courier New\">((HttpWebRequest)e.Request).CookieContainer =      <br \/>&#160;&#160;&#160;&#160; ((ClientFormsIdentity)Thread.CurrentPrincipal.Identity).AuthenticationCookies;       <br \/><\/font><font face=\"Courier New\">&#160;&#160;&#160; }      <br \/>}<\/font><\/p>\n<p>This works by adding the partial OnContextCreated method, which is called in the MusicStoreEntities constructor, and hooking up to the SendingRequest event, to set the cookie for each request.<\/p>\n<p>That\u2019s it, pretty easy.<\/p>\n<h4>Manually setting the Cookie:<\/h4>\n<p>If however using Client Application Services is not an option \u2013 for example you\u2019re in Silverlight or you can only use the Client Profile \u2013 you will have to manually get and set the cookie.<\/p>\n<p>To do this change the example above to look like this instead:<\/p>\n<p><font face=\"Courier New\">public partial class MusicStoreEntities      <br \/>{       <br \/>&#160;&#160;&#160; partial void OnContextCreated()       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.SendingRequest +=       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new EventHandler&lt;SendingRequestEventArgs&gt;(OnSendingRequest);&#160; <br \/><\/font><font face=\"Courier New\">&#160;&#160;&#160; }      <br \/>&#160;&#160;&#160; public void OnSendingRequest(object sender, SendingRequestEventArgs e)       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; e.RequestHeaders.Add(&quot;Cookie&quot;, GetCookie(&quot;Alex&quot;, &quot;password&quot;));       <br \/>&#160;&#160;&#160; }       <br \/>&#160;&#160;&#160; string _cookie;       <br \/>&#160;&#160;&#160; string GetCookie(string userName, string password)       <br \/>&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (_cookie == null)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string loginUri = string.Format(&quot;{0}\/{1}\/{2}&quot;,       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;<\/font><a href=\"http:\/\/localhost:1397&quot;\"><font face=\"Courier New\">http:\/\/localhost:1397&quot;<\/font><\/a><font face=\"Courier New\">,      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;Authentication_JSON_AppService.axd&quot;,       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;Login&quot;);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WebRequest request = HttpWebRequest.Create(loginUri);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; request.Method = &quot;POST&quot;;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; request.ContentType = &quot;application\/json&quot;; <\/font><\/p>\n<p><font face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string authBody = String.Format(      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &quot;{{ &quot;userName&quot;: &quot;{0}&quot;, &quot;password&quot;: &quot;{1}&quot;, &quot;createPersistentCookie&quot;:false}}&quot;,       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; userName,       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; password);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; request.ContentLength = authBody.Length; <\/font><\/p>\n<p><font face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; StreamWriter w = new StreamWriter(request.GetRequestStream());      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; w.Write(authBody);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; w.Close(); <\/font><\/p>\n<p><font face=\"Courier New\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; WebResponse res = request.GetResponse();      <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (res.Headers[&quot;Set-Cookie&quot;] != null)       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; _cookie = res.Headers[&quot;Set-Cookie&quot;];       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; else       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; throw new SecurityException(&quot;Invalid username and password&quot;);       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; }       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160; return _cookie;       <br \/>&#160;&#160;&#160; }       <br \/>}<\/font><\/p>\n<p><font face=\"Courier New\"><\/font><\/p>\n<p>This code is admittedly a little more involved. But it you break it down it all makes sense.<\/p>\n<p>The code adds the cookie to the headers whenever a request is issued.<\/p>\n<p>The hardest part is actually acquiring the cookie. The GetCookie() method checks whether we have a cookie, if not it creates a request to the Authentication endpoint, passing the username and password in a JSON body.<\/p>\n<p>If authentication is successful the response will include a \u2018Set-Cookie\u2019 header, that contains the cookie.<\/p>\n<h4>Summary:<\/h4>\n<p>We\u2019ve just walked through using Forms Authentication with an OData service.<\/p>\n<p>That included: integrating security with an existing website, enabling both browser and active clients \u2013 based on DataServiceContext \u2013 and authenticating from any .NET client.<\/p>\n<p>Next up we\u2019ll start looking at things like OAuth and OAuthWrap\u2026<\/p>\n<p><a href=\"https:\/\/twitter.com\/adjames\"><strong>Alex James<\/strong><\/a>     <br \/>Program Manager     <br \/>Microsoft.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Our goal in this post is to re-use the Forms Authentication already in a website to secure a new Data Service. To bootstrap this we need a website that uses Forms Auth. Turns out the MVC Music Store Sample is perfect for our purposes because: It uses Forms Authentication. For example when you purchase an [&hellip;]<\/p>\n","protected":false},"author":512,"featured_media":3253,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[15,34,48],"class_list":["post-1183","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-odata","tag-authentication","tag-forms-authentication","tag-odata"],"acf":[],"blog_post_summary":"<p>Our goal in this post is to re-use the Forms Authentication already in a website to secure a new Data Service. To bootstrap this we need a website that uses Forms Auth. Turns out the MVC Music Store Sample is perfect for our purposes because: It uses Forms Authentication. For example when you purchase an [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/1183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/users\/512"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/comments?post=1183"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/posts\/1183\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media\/3253"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/media?parent=1183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/categories?post=1183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/odata\/wp-json\/wp\/v2\/tags?post=1183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}