withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!
https://astro.build
Other
46.76k stars 2.48k forks source link

Server cookie isn't retrieved when redirecting from external request #8608

Closed seancdavis closed 1 year ago

seancdavis commented 1 year ago

Astro Info

Astro                    v3.0.10
Node                     v18.17.0
System                   macOS (arm64)
Package Manager          yarn
Output                   server
Adapter                  @astrojs/netlify
Integrations             @astrojs/tailwind

Example project:

Astro                    v3.1.1
Node                     v18.17.0
System                   macOS (arm64)
Package Manager          yarn
Output                   server
Adapter                  none
Integrations             @astrojs/tailwind

If this issue only occurs in one browser, which browser is a problem?

Different issues in different browsers, noted in example README

Describe the Bug

I have a custom auth solution that is designed to work like this:

  1. User adds email
  2. Email is sent to the user with link (with a token)
  3. User clicks link, which hits an auth endpoint. If the token is valid, a cookie is set and they are redirected to the home page, signed in.

When I mimic the email behavior by printing a link on the screen, everything works fine.

But when I mimc an email service (using Nodemailer + Ethereal in the test), I run into a consistent issue. Flow is like this:

  1. User lands on the auth page as expected.
  2. Auth page does what it should and sets the cookie. I can log the cookie to the console from the auth page.
  3. Redirects, as expected to the home page.
  4. Home page can't get the cookie (which is set).
  5. Refreshing doesn't help, including a hard refresh
  6. What ultimately solves it is clicking another link in the UI.

This is all happening locally and with SSR. I haven't tried deploying it yet.

What's the expected result?

The cookie should be able to be set manually (which is a problem in Safari).

In Chromium browsers, the (server) cookie should be able to be set, then the page redirected, with the ending route able to retrieve the cookie.

Link to Minimal Reproducible Example

https://github.com/seancdavis-stackbit/astro-bug-recreation

Participation

matthewp commented 1 year ago

Hi @seancdavis which part do you think Astro is doing wrong here?

seancdavis commented 1 year ago

Hey @matthewp — The home page looks for a cookie called test-cookie.

const cookie = Astro.cookies.get('test-cookie');

Another page (set-cookie), sets the same cookie then redirects to the home page.

Astro.cookies.set('test-cookie', 'Cookie is Set', {
  path: '/',
  maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
  secure: true,
  httpOnly: true,
  sameSite: 'strict',
});
return Astro.redirect('/');

Then the process repeats. If accessing /set-cookie by clicking on an internal link, everything works fine. If first landing on the /set-cookie page from an external source, the home page doesn't properly retrieve the cookie. const cookie = Astro.cookies.get('test-cookie'); has a value of undefined.

seancdavis commented 1 year ago

There's a related issue in that this same example isn't able to set cookies on Safari at all. Happy to log separately if it seems like a separate issue.

seancdavis commented 1 year ago

Hey @matthewp: Checking in — any more investigation needed to triage this issue?

matthewp commented 1 year ago

I did take a look. If you remove the sameSite restriction it works. I'm not an expert on cookies, but the below headers are part of the request for /set-cookie. My suspicion is that the browser ignores the cookie because of these headers and the sameSite config option being used.

Screen Shot 2023-09-27 at 5 02 30 PM

I don't think this has anything to do with Astro, so closing. If you can create a reproduction that takes 3rd party sites out of the equation please file a new issue.

seancdavis commented 1 year ago

That was it! Switched sameSite to lax and it fixes the issue.

seancdavis commented 1 year ago

I was also able to resolve the issue with Safari. Although I couldn't find any official/external explanation, after some trial and error, it seems like the secure option must match the protocol for Safari.

By setting secure conditionally based on environment, it seems to now be setting the cookies as I expect.

I tested this against an https URL and set secure: true, also with success. (And with sameSite: 'lax')