How to Fix: Subdomain Not Sending Cookie with Request to Parent Domain

Cookies are a critical component of web applications, enabling stateful interactions (e.g., authentication, session management, and user preferences) between clients and servers. However, a common issue arises when a subdomain fails to send cookies to its parent domain, disrupting functionality like single sign-on (SSO), cross-domain tracking, or shared user sessions.

This blog will break down why subdomains may fail to send cookies to parent domains, walk through step-by-step fixes, and provide actionable testing strategies to ensure your cookies work seamlessly across domains.

Table of Contents#

  1. Understanding the Problem: Subdomain → Parent Domain Cookie Flow
  2. Root Causes of Cookie Non-Delivery
  3. Step-by-Step Fixes
  4. Testing the Fix
  5. Common Pitfalls to Avoid
  6. Conclusion
  7. References

Before diving into fixes, let’s clarify the scenario:

  • Parent Domain: The primary domain (e.g., example.com).
  • Subdomain: A domain nested under the parent (e.g., app.example.com or api.example.com).

When a subdomain (e.g., app.example.com) sends an HTTP request to its parent domain (e.g., example.com), cookies associated with the parent domain (or shared across subdomains) should be included in the request. If they aren’t, it’s typically due to misconfigured cookie attributes.

Cookies rely on specific attributes to determine when and where they are sent. Misconfiguring these attributes is the most common cause of subdomains failing to send cookies to parent domains:

AttributePurposeHow Misconfiguration Causes Issues
DomainSpecifies which domains can receive the cookie.If set to app.example.com (subdomain only), the cookie won’t be sent to example.com.
PathRestricts the cookie to specific URL paths.If set to /app, the cookie won’t be sent when requesting example.com/ (root path).
SameSiteControls cookie sending in cross-site requests.SameSite=Strict may block cookies in some navigation scenarios (even for same-site subdomains).
SecureEnsures the cookie is only sent over HTTPS.If Secure is set but the parent domain uses HTTP, the cookie won’t be sent.
HttpOnlyPrevents client-side JavaScript from accessing the cookie (security).Not directly related to delivery, but misconfiguring other attributes alongside HttpOnly can hide issues.

Step-by-Step Fixes#

To resolve the issue, ensure your cookie is configured with the correct attributes. Below is a detailed breakdown of each fix, including code examples for common server-side languages.

3.1 Set the Domain Attribute Correctly#

The Domain attribute determines which domains can receive the cookie. To allow the parent domain (example.com) and all subdomains (e.g., app.example.com) to share the cookie:

  • Set Domain=example.com (without a subdomain). This ensures the cookie is sent to:

    • The parent domain (example.com).
    • All subdomains (app.example.com, api.example.com, etc.).
  • Avoid: Setting Domain=app.example.com (limits to the subdomain) or omitting Domain (restricts to the exact domain that set the cookie).

Example: Setting Domain in Server-Side Code#

Language/FrameworkCode Snippet
Node.js/Expressjavascript res.cookie('sessionId', 'abc123', { domain: 'example.com' });
Python/Flaskpython response.set_cookie('sessionId', 'abc123', domain='example.com')
PHPphp setcookie('sessionId', 'abc123', 0, '/', 'example.com');
Java/Spring Bootjava response.addCookie(new Cookie("sessionId", "abc123") {{ setDomain("example.com"); }});

3.2 Configure the Path Attribute#

The Path attribute restricts the cookie to specific URL paths. To ensure the cookie is sent for all requests to the parent domain (including the root path, /), set:

  • Path=/ (covers all paths under the domain).

  • Avoid: Narrow paths like /app or /api, which block the cookie from being sent to the parent domain’s root (example.com/).

Example: Adding Path=/#

Update the cookie configuration to include path: '/':

Node.js/Express Example:

res.cookie('sessionId', 'abc123', {  
  domain: 'example.com',  
  path: '/'  // Critical: Allows cookie on all paths (e.g., /, /about, /api)  
});  

3.3 Adjust the SameSite Attribute#

The SameSite attribute controls cookie behavior in cross-site requests. For subdomain-to-parent-domain communication (considered "same-site"), use:

  • SameSite=Lax: Allows cookies in top-level navigations (e.g., clicking a link from app.example.com to example.com).
  • SameSite=None: Use only if the cookie needs to be sent in cross-site requests (e.g., embedded iframes). Requires Secure (see Section 3.4).

Avoid SameSite=Strict unless you explicitly want to block cookies in most cross-site scenarios (even same-site subdomains may be affected).

Example with SameSite=Lax#

// Node.js/Express example with SameSite=Lax  
res.cookie('sessionId', 'abc123', {  
  domain: 'example.com',  
  path: '/',  
  sameSite: 'Lax'  // Allows cookie in top-level navigations  
});  

3.4 Enforce Secure for HTTPS#

If SameSite=None is used, browsers require the Secure attribute (cookies sent only over HTTPS). Even for SameSite=Lax, Secure is recommended for security.

  • Ensure your parent and subdomains use HTTPS. Tools like Let’s Encrypt provide free SSL certificates.

  • Example with Secure:

    res.cookie('sessionId', 'abc123', {  
      domain: 'example.com',  
      path: '/',  
      sameSite: 'Lax',  
      secure: true  // Cookie only sent over HTTPS  
    });  

Ensure the cookie is set by the parent domain or a shared subdomain. If the cookie is set by app.example.com, it must include Domain=example.com to be sent to example.com.

Common Mistake: Setting the cookie on app.example.com without Domain=example.com—this limits the cookie to app.example.com only.

Testing the Fix#

After configuring the cookie, verify it’s being sent to the parent domain using browser developer tools:

Step 1: Inspect Cookies in the Browser#

  1. Open Chrome/Firefox DevTools (F12 or Ctrl+Shift+I).
  2. Go to the Application tab (Chrome) or Storage tab (Firefox).
  3. Under Cookies, select example.com and check:
    • Domain is set to example.com.
    • Path is /.
    • SameSite, Secure, and other attributes match your configuration.

Step 2: Check Network Requests#

  1. In DevTools, go to the Network tab.
  2. From app.example.com, trigger a request to example.com (e.g., load example.com in a new tab or call an API endpoint).
  3. Select the request in the Network tab and check the Request Headers for Cookie: sessionId=abc123 (your cookie name/value).

Step 3: Test with curl (Command Line)#

Use curl to verify the cookie is sent:

# Replace with your parent domain and subdomain  
curl -I https://example.com --cookie "sessionId=abc123; Domain=example.com; Path=/"  

Look for Set-Cookie in the response headers to confirm the cookie is being sent.

Common Pitfalls to Avoid#

  • Forgetting Path=/: If Path is set to /app, the cookie won’t be sent to example.com/ (root path). Always use Path=/ for broad coverage.
  • Mismatched Protocols: If Secure is enabled, ensure both the subdomain and parent domain use HTTPS. HTTP requests will block the cookie.
  • Legacy Domain Dots: Older docs recommend Domain=.example.com (with a leading dot), but modern browsers ignore the dot. Use Domain=example.com for compatibility.
  • SameSite=Strict Overkill: Strict blocks cookies in most cross-site scenarios. Use Lax for same-site subdomain-parent communication.

Conclusion#

The root cause of subdomains failing to send cookies to parent domains is almost always misconfigured cookie attributes. By ensuring Domain=example.com, Path=/, SameSite=Lax, and Secure (for HTTPS), you’ll resolve the issue. Always test with browser dev tools or curl to confirm the cookie is being sent.

References#