Home     Products      Support      Corporate     Sign In 
Support Knowledge Base, Article 666
Product
General
Title
Sharing Cookies Across Domains
Solution

Sharing Cookies Across Domains

By Wayne Berry
Introduction

In this session I will show you how to share the same cookie across multiple sub-domains and multiple domains. I will also discuss sharing state information across web farms using SQL Server. The examples in this session highlight the power of redirection within Active Server Pages and enforce the concepts that are related to cookie manipulation.

Sharing Cookies Between Sub-domains

A sub-domain is a subset of the main domain that has a separate IP. For example, if you purchase the domain myserver.com from the INTERNIC you can break it down into sub domains like the following:

  • www.myserver.com
  • smtp.myserver.com
  • client1.myserver.com
  • secure.myserver.com

You can issue cookies on the www.myserver.com sub-domain like this:

Example 1:

<%
Response.Cookies("UID") = 1
%>

This cookie will only last for the length of the user session, defined by the amount of time that browser stays open. The cookie's scope is just the www.myserver.com domain. If you request this cookie on other sub domains within the same domain you will not be able to get the value associated to UID.

You can solve this problem by substituting the code in Example 2 for the code in Example 1.

Example 2:

<%
Response.Cookies("UID") = 1
Response.Cookies("UID").Domain = ".myserver.com"
%>

By setting the Domain property of the cookie to the domain of the sub domain you instruct the browser to send the cookie to all sub domains. Notice the period before the domain name, this is very important. RFC 2109 specifies that the Domain setting on cookies must have two periods.

Sharing Cookies Between Domains

Sharing cookies between domains is trickier then sharing cookies between sub-domains of a single domain. An example of this working is the three domains owned by Microsoft: msnbc.com, msn.com, and microsoft.com. These three domains share the same cookie for each user. To share a cookie between domains, you will need two domains. For example, myserver.com and slave.com. One of the domains will issue the cookies and the other domain will ask the first domain what cookie should be issued to the client. In this case myserver.com will issue the cookie and slave.com will use the cookie issued by myserver.com. Here is the code that myserver.com will use to issue the cookie:

Example 3:

cookie.inc

<%
UID = Request.Cookies("UID")

If ((IsNull(UID)) OR (Len(UID) = 0)) Then

Set UIDGen = Server.CreateObject("SMUM.Example.1")

'--- Here is the method call to assign the cookie
UID = UIDGen.GetCookie()

Response.Cookies("UID") = UID
Response.Cookies("UID").Domain = ".myserver.com"
Response.Cookies("UID").Expires = "December 31, 1999"

End If
%>

The object created in this example was demonstrated in the Apr 22, 1997 issue of 15 Seconds entitled: "Active Server Components with VB 5.0." You can download just the object from this issue and use it in the code above. When the GetCookie method is called, a random 128-bit number is produced that is guaranteed to be unique to the user. UID stands for Unique IDentifier.

Notice that this code is contained in a cookie.inc file that can be included at the top of all Active Server Pages within the myserver.com domain.

Requesting Cookie from Another Domain

Now, the interesting part, how does slave.com get the same cookie from domain.com? This technique is implemented through a set of redirects. Let's take a look at the code that is implemented on slave.com:

Example 4:

getcookie.inc

<%
UID = Request.Cookies("UID")

If ((IsNull(UID)) OR (Len(UID) = 0)) Then

strURL = Request.ServerVariables("URL"))
strQueryString = Request.ServerVariables("QUERY_STRING"))


If (Len(strQueryString>0) Then
strReturn = Server.URLEncode(strURL & "?" & strQueryString)
Else
strReturn = Server.URLEncode(strURL)
End If

Response.Redirect("http://myserver.com/slave.asp?Return=" & strReturn)

End If
%>

Notice that we do not actually assign the cookie in this page. Instead, if there is no cookie available, we redirect to a special page on myserver.com. We also bundle up the address of the page we are on for future use. Let's take a look at slave.asp:

Example 5:

slave.asp

<%
strReturn = Server.URLEncode(Request("Return"))

Response.Redirect("http://slave.com/return.asp?Return=" & strReturn & strReturn & "&UID=" & UID)

End If
%>

Notice that we included cookie.inc from Example 3. Since slave.asp resides on myserver.com, the cookie that is issued in cookie.inc has a scope of just myserver.com. If the user didn't have a cookie on myserver.com they are given one because of the code in cookie.inc. This way if they are visiting slave.com first, and then visit myserver.com, they will have the same cookie. If the user already has a cookie from myserver.com and they visit slave.com for the first time, they will be redirected to slave.asp on myserver.com where that cookie will be retrieved. Because the cookie only has the scope of the domain that it is issued on, we have to redirect to the master domain to get the cookie and then redirect back to the slave domain. Here is the code for return.asp that resides on slave.com:

Example 6:

return.asp

<%
UID = Request("UID")
strReturn = Request("Return")

Response.Cookies("UID") = UID
Response.Cookies("UID").Domain = ".slave.com"
Response.Cookies("UID").Expires = "December 31, 1999"

Response.Redirect(strReturn)
%>

Notice that return.asp sets the UID cookie to the UID that is passed from slave.asp on myserver.com. Because myserver.com passes the same UID as it uses for a cookie, both servers end up with the same cookie for the same user. In other words, the user ends up with two cookies on their machine. One from myserver.com and one from slave.com, and they equal the same UID. Also note that the final redirect is back to the page the user requested on slave.com. The redirect uses the return information that the getcookie.inc bundled up. Return.asp should always be called from slave.asp and for no other reason.

In summary, every Active Server Page should include getcookie.inc at the top of the page and, if a cookie needs to be set, getcookie.inc will handle the problem.

Error Handling

Because we wanted to make these examples easy to understand, we didn't add any error handling. However, if the client browser did not accept cookies, then the code demonstrated above would cause an endless loop of redirection. For this reason we need to change Example 6 to read:

Example 7:

return.asp

<%
UID = Request("UID")
strReturn = Server.URLEncode(Request("Return"))

Response.Cookies("UID") = UID
Response.Cookies("UID").Domain = ".slave.com"
Response.Cookies("UID").Expires = "December 31, 1999"

Response.Redirect("http://slave.com/test.asp?Return=" & strReturn)

End If
%>

Now we can add test.asp that tests to make sure that the cookie took. Here is what the code looks like:

Example 8:

return.asp

<%
UID = Request.Cookies("UID")

If Not ((IsNull(UID)) OR (Len(UID) = 0)) Then
strReturn = Request("Return")
Response.Redirect(strReturn)
End If
%>

<HTML>
<BODY>

<H1>You must use a browser that accepts cookies on http://slave.com</H1>

</BODY>
</HTML>

Performance

If the user doesn't have a cookie from myserver.com and he requests a page that has cookie.inc included, they will be issued a cookie. This scenario is the best case scenario. If the user doesn't have a cookie from slave.com and he requests a page that has getcookie.inc included, and they haven't visited myserver.com, then they will have to undergo four redirects and be issued two cookies. This is the worst case scenario.

Fortunately, the worst case scenario only happens once. All requests after that do not have to undergo any redirects. In the worst case scenario, it is best to use a technique that produces a random number quickly, because the user will be confused if they see to many redirections on their first page request. The technique of using a COM object to issue a random UID is much quicker then getting a IDENTITY value from SQL Server.

Sharing More Than One Cookie

The more cookies you try to share with this technique, the harder the problem becomes. It is recommend that you use a different approach to storing state and user information besides cookies. Once you have the UID of the user, you can use the UID to get other information about that user from SQL Server. Using the UID as a primary key to the database enables you to use only one cookie in your web application. This makes the technique mentioned above usable.

Web Farms

Web farms are more than one web server serving the same information with the same domain name. Each machine has a separate IP, but the domain name server uses a technique called round-robin to give clients a different IP with every request. Because the clients receive a different IP for every request they are directed to a different server for each page. Web farms distribute the requested load across multiple machines making the site appear faster.

Because session variables are stored in the RAM on each machine, session variables that are set on one machine are not the same on another machine in a web farm. For this reason you can not use session variables in a web farm. However, instead of session variables you can use a cookie that is a primary key to a SQL Server database that stores the state information for the user. As long as all the machines in the web farm are writing to the same SQL Server you can share state information between all the machines in a web farm. And, because each machine has the same domain name, the client returns the same cookie to each machine making the distribution of the primary keys a trivial matter.

Further Reading
  • RFC 2109
About The Author

As a former Microsoft design engineer, and the director of development for FreeShop, Wayne Berry's expertise includes software design, development, marketing and online business. The web site he created as a hobby to assist in distributing information to Active Server Page developers became his first product, 15 Seconds. The sale of 15 Seconds to Internet.com allowed Berry time to develop his latest product, XBuilder, and Kulshan.com, a community web-site for his hometown, Bellingham, Washington.

Created : 7/15/2003 5:46:16 PM (last modified : 7/15/2003 5:46:14 PM)
Rate this article!
 
Comments