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#
- Understanding the Problem: Subdomain → Parent Domain Cookie Flow
- Root Causes of Cookie Non-Delivery
- Step-by-Step Fixes
- Testing the Fix
- Common Pitfalls to Avoid
- Conclusion
- References
Understanding the Problem: Subdomain → Parent Domain Cookie Flow#
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.comorapi.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.
Root Causes of Cookie Non-Delivery#
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:
| Attribute | Purpose | How Misconfiguration Causes Issues |
|---|---|---|
Domain | Specifies which domains can receive the cookie. | If set to app.example.com (subdomain only), the cookie won’t be sent to example.com. |
Path | Restricts the cookie to specific URL paths. | If set to /app, the cookie won’t be sent when requesting example.com/ (root path). |
SameSite | Controls cookie sending in cross-site requests. | SameSite=Strict may block cookies in some navigation scenarios (even for same-site subdomains). |
Secure | Ensures the cookie is only sent over HTTPS. | If Secure is set but the parent domain uses HTTP, the cookie won’t be sent. |
HttpOnly | Prevents 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.).
- The parent domain (
-
Avoid: Setting
Domain=app.example.com(limits to the subdomain) or omittingDomain(restricts to the exact domain that set the cookie).
Example: Setting Domain in Server-Side Code#
| Language/Framework | Code Snippet |
|---|---|
| Node.js/Express | javascript res.cookie('sessionId', 'abc123', { domain: 'example.com' }); |
| Python/Flask | python response.set_cookie('sessionId', 'abc123', domain='example.com') |
| PHP | php setcookie('sessionId', 'abc123', 0, '/', 'example.com'); |
| Java/Spring Boot | java 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
/appor/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 fromapp.example.comtoexample.com).SameSite=None: Use only if the cookie needs to be sent in cross-site requests (e.g., embedded iframes). RequiresSecure(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 });
3.5 Verify Server-Side Cookie Configuration#
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#
- Open Chrome/Firefox DevTools (F12 or
Ctrl+Shift+I). - Go to the Application tab (Chrome) or Storage tab (Firefox).
- Under Cookies, select
example.comand check:Domainis set toexample.com.Pathis/.SameSite,Secure, and other attributes match your configuration.
Step 2: Check Network Requests#
- In DevTools, go to the Network tab.
- From
app.example.com, trigger a request toexample.com(e.g., loadexample.comin a new tab or call an API endpoint). - 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=/: IfPathis set to/app, the cookie won’t be sent toexample.com/(root path). Always usePath=/for broad coverage. - Mismatched Protocols: If
Secureis enabled, ensure both the subdomain and parent domain use HTTPS. HTTP requests will block the cookie. - Legacy
DomainDots: Older docs recommendDomain=.example.com(with a leading dot), but modern browsers ignore the dot. UseDomain=example.comfor compatibility. SameSite=StrictOverkill:Strictblocks cookies in most cross-site scenarios. UseLaxfor 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.