If a run an application containing an iframe on 127.0.0.1:5500
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script>
document.addEventListener("DOMContentLoaded", () => {
// This here is to demonstrate that the a request to localhost:3000 will
// give a CORS error
fetch("http://localhost:3000/req1").then((res) => {
console.log(res);
});
})
</script>
<body>
<h1>I am the outer application</h1>
<iframe src="https://localhost:3000" width="100%" height="500px"></iframe>
</body>
</html>
And the application at localhost:3000
makes requests to /req1
, /req2
/req3
,
and these will return some data, as well as setting a cookie, and no cross origin headers.
eg.
//req1
export async function GET() {
const x = NextResponse.json({ error: 'I am req 1 data' }, { status: 200 })
x.cookies.set("my-cookie-1", "hello world");
return x;
}
//req2
export async function GET() {
const x = NextResponse.json({ error: 'I am req 2 data' }, { status: 200 })
x.cookies.set("my-cookie-2", "hello world", {
"sameSite":"none",
"secure": true,
});
return x;
}
What I observe is that the iframe is able to make the requests and the data and cookies are retrieved fine. They’re considered same-site requests in this sense.
However, unless we add secure: true
and sameSite: "none"
the cookies are not attached on subsequent requests.
In Chrome’s devtools we see the message:
The cookie didn’t specifiy a “SameSite” attribute when it was sotred and was defaulted to “SameSite=Lax,” and was blocked because the request was made from a different site and was not initiated by a top-level navigation. The cookie had to be set with “SameSite=None” to enable cross-site usage.
Why does the cookie treat this as a cross-site request, when the request itself does not?
I have a reproduction for this here:
https://github.com/dwjohnston/cookies-and-iframes