HttpFixer → Blog → Headers → SameSite Cookie Issues in Iframes — Why Your Embedded App Loses Session
Headers SameSite Cookie Issues in Iframes — Why Your Embedded App Loses Session
Updated April 2026
Reading this? Verify your fix in real-time. Scan your cookie headers → HeadersFixer
You embedded your dashboard inside a partner's page. Users are logged out the moment the iframe loads. Their browser sent the session cookie on the top-level navigation but not inside the iframe. SameSite=Lax is working as designed — blocking your embed.
Understanding the SameSite values
| Value | Sent on top-level navigation | Sent in iframes (cross-site) | CSRF protection |
|---|---|---|---|
| Strict | Same-site only | No | Maximum |
| Lax (default) | Yes (GET only) | No | Good |
| None; Secure | Yes | Yes | None from SameSite — need CSRF tokens |
The fix for embedded apps
# Cookies used inside cross-site iframes need SameSite=None Set-Cookie: embed_session=abc123; SameSite=None; Secure; HttpOnly; Path=/ # In Chrome 2026 — also add Partitioned: Set-Cookie: embed_session=abc123; SameSite=None; Secure; HttpOnly; Partitioned; Path=/
Implementation by framework
Express / Node.js
// Only set None for cookies that need iframe access
res.cookie("embed_session", sessionId, { sameSite: "none", // must be lowercase string secure: true, httpOnly: true, path: "/"
});
// Session cookie stays Lax
res.cookie("session", sessionId, { sameSite: "lax", secure: true, httpOnly: true
});
FastAPI / Python
response.set_cookie( key="embed_session", value=session_id, samesite="none", secure=True, httponly=True, path="/" )
Django
# settings.py — for embedded apps only # Do NOT change SESSION_COOKIE_SAMESITE globally to "None" # Set it per-cookie in your view: response.set_cookie( "embed_session", value=session_id, samesite="None", secure=True, httponly=True )
You also need X-Frame-Options removed (or set to SAMEORIGIN)
# If you have X-Frame-Options: DENY on your app — the iframe will be blocked entirely # For embedded apps, either: # 1. Remove X-Frame-Options # 2. Set to SAMEORIGIN (allows same-domain embeds) # 3. Use CSP frame-ancestors to allow specific partner domains: Content-Security-Policy: frame-ancestors 'self' https://partner.com;
CSRF protection without SameSite
When you use SameSite=None, you lose CSRF protection from cookies. You need explicit CSRF tokens:
// Generate a CSRF token per session and include it in responses
// The iframe JavaScript must send it as a header with state-changing requests
app.post("/api/action", (req, res) => { const csrfToken = req.headers["x-csrf-token"]; const storedToken = req.session.csrfToken; if (!csrfToken || csrfToken !== storedToken) { return res.status(403).json({ error: "CSRF token invalid" }); } // process request
}); Scan your cookie headers → HeadersFixer