Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make cookie store web-only #2110

Open
wants to merge 10 commits into
base: trunk
Choose a base branch
from
Open

Conversation

brandonpayton
Copy link
Member

@brandonpayton brandonpayton commented Dec 27, 2024

Motivation for the change, related issues

A cookie store is needed on the web where custom Response objects may not be assigned Set-Cookie headers. Otherwise, Set-Cookie headers received in PHP responses are effectively discarded. But a cookie store isn't needed for Playground CLI, and applying the same cookies to all requests to a CLI-based server interferes with clients that want to use other WP auth schemes.

This PR gives the browser-based PHP worker the responsibility for maintaining a cookie store per Playground scope.

Fixes #1611

cc @dcalhoun

Implementation details

This PR makes the cookie store a browser-based PHP worker concern so it can manage which cookie store to apply to which requests.

Originally, I wanted to make the Service Worker responsible for the synthetic cookie store because it is responsible for all request routing and generally sits between the browser client and the PHP "server", but it turned out to be quite awkward because:

  • the Service Worker doesn't currently know when Playground site scopes come and go, making cleanup difficult
  • Service Workers can be terminated and restarted while client tabs are still open. This meant that we'd have to persist cookies in something like IndexedDB, and both service worker lifetime uncertainty and ignorance about the lifetime of site scopes made it difficult to know when old cookie stores could be cleared.

If the cookie store is kept with the PHP worker, then the cookies will naturally come and go as Playground sites are loaded and unloaded.

Testing Instructions (or ideally a Blueprint)

  • CI

It is needed on the web where custom Response objects
may not be assigned Set-Cookie headers. Otherwise, cookies
from PHP requests would not be respected.
But a cookie store isn't needed for Playground CLI,
and applying the same cookies to all requests to a CLI-based
server interferes with clients that want to use other
WP auth schemes.
@brandonpayton
Copy link
Member Author

So far, the biggest remaining challenge for this PR is maintaining the cookie store even if the service worker is terminated due to inactivity. Apparently, this can happen even if browser tabs from a service worker's scope remain open.

From https://web.dev/learn/pwa/service-workers#lifespan:

Service workers are terminated if they've been idle for a few seconds, or if they've been busy for too long. Timings for this vary between browsers. If a service worker has been terminated and an event occurs that would start it up, it restarts.

I'm not sure how much this is a problem in practice, but I'd rather not find out by testing on users in production.

The best thing I can think of at the moment is to use IndexedDB to maintain a cookie store, but if we do that, it would be good to have a way to clear cookies stored by a previous browser session before they can be used for the current session.

@brandonpayton
Copy link
Member Author

There are some unit tests that fail because of this change:
https://github.com/WordPress/wordpress-playground/actions/runs/12512026649/job/34906842188#step:4:405

At least some of the failures could be expected because they implicitly depend on cookie management being provided by @php-wasm/node. To fix this, some options are:

  • convert login tests to e2e tests
  • update the tests to manage their own cookies

@brandonpayton
Copy link
Member Author

I updated the failing unit tests to manage their own cookies. We also have e2e tests for login, so this should cover us.

@brandonpayton
Copy link
Member Author

brandonpayton commented Dec 27, 2024

So far, the biggest remaining challenge for this PR is maintaining the cookie store even if the service worker is terminated due to inactivity. Apparently, this can happen even if browser tabs from a service worker's scope remain open.

...snip...

The best thing I can think of at the moment is to use IndexedDB to maintain a cookie store, but if we do that, it would be good to have a way to clear cookies stored by a previous browser session before they can be used for the current session.

I think we can do the following:

  • Use the minimal idb library for a more usable interface to IndexedDB
  • Maintain scope-specific cookie stores in IndexedDB
  • Regularly trigger cookie store cleanup for scopes with no Service Worker clients remaining

One thing I'm not sure about:
I think we want to reset these cookie stores when the browser is restarted, and I'm not yet sure how to distinguish between:

  • a new browser starting with resumed tabs
  • a service worker that has been terminated and restarted during the same browser session

@brandonpayton
Copy link
Member Author

brandonpayton commented Dec 28, 2024

It seemed right for the service worker to manage a synthetic cookie store since it is responsible for all request routing. But if we do that, we need to worry about when Playground scopes come and go and when the service worker is terminated and restarted. And it requires cookie stores to be persisted to withstand a service worker being terminated and resumed in the middle of the browser session.

This is too much complexity.

For now, let's just move cookie management into the web-specific remote worker. Each worker is limited to a single scope and should live for as long as its Playground lives. That is also how long we want each cookie store to live.

So I plan to move cookie store management into that worker.

@brandonpayton
Copy link
Member Author

We have both unit and e2e tests for login that should cover these changes.

@brandonpayton
Copy link
Member Author

I confirmed that this patch fixes #1611 for Playground CLI. If I run the repro steps of that issue with Playground CLI, we get normal output from the REST API block types endpoint:
https://gist.github.com/brandonpayton/2b0f9abed27dae8ccb4e816164034a5b#file-output-json

@dcalhoun, once this PR is merged, we'll need to publish updated NPM packages. After that, @wp-now will need to update to use latest Playground packages for this auth path to work there. AFAIK, @wp-now is not actively maintained, and we'd like to merge it into Playground CLI so there is only one CLI tool.

@brandonpayton brandonpayton marked this pull request as ready for review December 31, 2024 19:14
@dcalhoun
Copy link
Member

dcalhoun commented Jan 2, 2025

@dcalhoun, once this PR is merged, we'll need to publish updated NPM packages. After that, @wp-now will need to update to use latest Playground packages for this auth path to work there. AFAIK, @wp-now is not actively maintained, and we'd like to merge it into Playground CLI so there is only one CLI tool.

@brandonpayton thank you for your work on this! That plan sounds good. I was unaware of plans to merge the CLIs, but it makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

Incorrect user capabilities result in unexpected 401 responses from the REST API
2 participants