if you continue to use this site, you consent to our use of cookies
OK
Knowledge Sharing
2.6.2024

Navigating the Crossroads: Mastering Cross-Domain Cookies in Web Applications

Navigating the Crossroads: Mastering Cross-Domain Cookies in Web Applications

Intro

In the ever-evolving realm of web development, where boundaries between applications blur and user experiences span multiple domains, the ability to set cookies across different origins has become a crucial facet of modern web architecture. Web applications often need to interact with multiple domains to provide a seamless user experience. However, setting cookies across domains can be challenging due to security concerns and browser restrictions.

The essence of cross-domain cookie settings lies in the seamless exchange of information between distinct web apps. Whether it be an e-commerce platform using external payment systems, a single-page application interfacing with multiple micro-frontends, or a federated authentication system, the ability to establish a unified state across diverse domains is paramount. 

Yet, as the web matured, so have the mechanisms to safeguard user data and privacy, leading to solid security protocols. While browsers have become more observant in protecting users from potential security issues, developers must adeptly navigate these safeguards to ensure that the exchange of cookies aligns with both security best practices and the user’s expectations of a unified digital experience.

This article will explore the techniques and best practices for setting cookies for another domain in your web application. We will consider my experience in developing a micro-frontend app. Welcome to the realm where cross-domain cookie setting is not just a technical challenge but a gateway to unlocking the full potential of a seamless user experience.

Browser limitations

Before diving into the implementation, it’s crucial to understand the limitations and security considerations associated with cross-domain cookie settings. Here are some key aspects to consider:

  1. Same-Origin Policy (SOP)

    The Same-Origin Policy is a fundamental security measure implemented by web browsers. It restricts web pages from requesting a different domain than the one that served the original web page. It prevents a malicious website on the Internet from running JS in a browser to read data from third-party services. This policy also extends to cookie access and settings. For example, http://company.com/page.html and http://company.com/another.html have the same origins, but http://company.com/page.html and http://company1.com/page.html have different origins.
  1. Cross-Origin Resource Sharing (CORS)

    CORS is a mechanism that allows servers to specify which origins can access their resources. Browsers block cross-origin requests without proper CORS configuration, including those for setting cookies.

Let’s consider useful security flags:

  1. SameSite Attribute: The SameSite cookie attribute was introduced to prevent cross-site request forgery (CSRF) attacks. It defines when a cookie should be sent with a cross-origin request. The values can be Strict, Lax, or None. Developers must be cautious with the None value, as it requires the Secure attribute and allows cookies to be sent with any cross-origin request.

  2. Secure Attribute: Cookies marked with the Secure attribute will only be sent over HTTPS connections. When setting cookies for another domain, ensure that the connection is secure to prevent interception of sensitive information.

  3. HttpOnly Attribute: The HttpOnly attribute prevents client-side scripts from accessing the cookie through the document.cookie API. This is a security measure to mitigate the risk of cross-site scripting (XSS) attacks. However, it can limit the ability to manipulate cookies using JavaScript.

  4. Path Attribute: The Path attribute specifies the subset of URLs a cookie applies to. Ensure that the Path is set appropriately to restrict the cookie to specific paths within the domain.

  5. Domain Attribute: The Domain attribute must be carefully configured when setting cookies for another domain. This attribute specifies the domain for which the cookie is valid. It is crucial to prevent unauthorized access to cookies by setting a specific domain. Here, we can also use subdomains — e.g., if we set domain=example.com, all our subdomains can access this domain (a.example.com, b.example.com, etc.)

  6. Expiration Time: Setting an appropriate expiration time for cookies is essential. A cookie that persists for an unnecessarily long time may pose security risks. Conversely, a duration that is too short may impact the user experience.

  7. Regulatory Compliance: Be aware of regional and international regulations related to privacy and data protection (e.g., GDPR, CCPA) and ensure that your cross-domain cookie practices comply with these regulations.

My story

Let’s dive into the challenges and requirements that characterize my application. The essence of my project lies in developing a system with different sub-apps, each hosting on separate subdomains. For instance, the authentication app ensures secure access, the order app facilitates seamless product and plan purchases, the account app oversees the management of user accounts, and the editor app empowers users to construct and customize websites.

The overarching objective of my project is to establish seamless communication among all the distinct applications. For instance, when a user initiates the authentication process in the auth app and completes it, it seamlessly redirects the user to the account app. The account app can distinguish whether the user is authenticated and allows users to open pages or handle redirects back to the auth app. From there, users can select and purchase plans in the order app. Successful purchasing triggers a message display in the account app. After successfully creating a website using the editor app, the next crucial step involves passing cookies to create websites hosted on separate domains accessible to our free users.

Utilizing cookies for data exchange between apps is a practical approach. By leveraging cookies, you establish a lightweight and convenient method for passing information seamlessly across different subdomains. This method simplifies the implementation process and can be an efficient solution for managing user authentication tokens, session data, or other relevant information. However, it’s important to prioritize security measures, such as encryption, to safeguard sensitive data transmitted via cookies. This approach aligns with the goal of creating a cohesive and user-friendly experience across your application ecosystem.

Using subdomains

Let’s get down to business and consider a case with using cookies for different subdomains:

Ensure the cookies have a domain attribute, including the primary domain and all relevant subdomains. For instance, if your primary domain is example.com, set the domain attribute of your cookies to “.example.com”. This allows cookies to be accessible across subdomains.

export const setCookie = ({ name, value, path = '/', domain, expires }: { name: string; value: string | boolean; path: string; domain: string; expires: string; }): void => { document.cookie = `${name}=${value};path=${path};domain=${domain}` + (expires ? `;expires=${expires}` : ''); }; setCookie({ name: 'foo', value: 'bar', path: '/', domain: '.example.com' });

With the appropriate domain configuration, you can successfully share cookies among subdomains like auth.example.com, account.example.com, and editor.example.com. This enables a unified user experience across your micro-apps.

By default, if you don’t set an expired value for a cookie, it becomes a session cookie. Session cookies persist only for the user’s session on the website. Once the user closes their browser, the session cookie is deleted. Add expires a field if you need to store cookies longer, for example, 30 days:

const date = new Date(); date.setDate(date.getDate() + 30); setCookie({ name: 'foo', value: 'bar', path: '/', domain: '.example.com', expires: date.toUTCString() });

Note: Consider setting the secure and HttpOnly flags on your cookies. The secure flag ensures that the cookie is only sent over HTTPS connections, enhancing security. The HttpOnly flag prevents client-side scripts from accessing the cookie, reducing the risk of cross-site scripting (XSS) attacks.

The following code is responsible for cleaning up our cookies:

export const deleteCookie = (name: string, path = '/'): void => { setCookie(name, '', path, undefined, 'Thu, 01 Jan 1970 00:00:01 GMT'); };

Technically, we just expire the passed cookie. The browser automatically removes expired cookies, ensuring they are no longer used for subsequent requests.

Different domains

Let’s delve into the most exciting part: how can we set cookies for another domain when you control both domains?

Ensure that you have administrative control over both example.com and another-example.com. This is crucial for implementing the necessary changes and configurations.

Step 1: Configuring CORS. Configure the server on another-example.com to include the appropriate CORS headers, granting permission for example.com to access resources seamlessly.

Access-Control-Allow-Origin: https://example.com

Step 2: Create a small HTML file (set-cookie.html) that can set appropriate cookies using postMessage API.

SameSite=None means the browser sends the cookie with cross-site and same-site requests. A secure flag should be set. Any cookie that requests SameSite=None but is not marked Secure will be rejected.

Note: A Secure cookie is only sent to the server with an encrypted request over the HTTPS protocol. Note that insecure sites (http:) can't set cookies with the Secure directive and, therefore, can't use SameSite=None.

Step 3: You need to host this HTML file on a server or hosting using a domain that you have access to (e.g., another-example.com)

Step 4: In the main application, we add a hidden iframe with the URL to the HTML file created in the previous step.

const iframe = document.createElement('iframe') iframe.setAttribute('src', "https://another-example.com/set-cookie.html") document.querySelector('body').append(iframe)

Step 5: In this iframe, we pass the necessary value through postMessage, which needs to be added to the cookies.

iframe.contentWindow.postMessage({ name: 'foo', value: 'bar' }, "https://another-example.com");

Congratulations! We are done, and users can now enjoy our app.

Conclusions

Setting cookies for another domain in your web application requires careful consideration of security implications and adherence to browser policies. Understanding and implementing the appropriate techniques can ensure a smooth cross-domain cookie-setting experience for your users. Always prioritize security and follow best practices to maintain a secure and reliable web application.

Rostyslav Moroziuk
Rostyslav Moroziuk
Frontend Developer

Let's engineer your breakthrough

Share your idea
arrow
09:45
AM
Lviv / HQ Office

79015, Smal-Stotskoho St. 1 Ukraine
09:45
AM
Wroclaw / Development Office

50-062, Plac Solny 15 Poland
STAND WITH
Ukraine