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

CSRF token API for service worker #2791

Open
OlliTietavainenVaadin opened this issue Oct 3, 2024 · 5 comments
Open

CSRF token API for service worker #2791

OlliTietavainenVaadin opened this issue Oct 3, 2024 · 5 comments
Labels
enhancement New feature or request hilla Issues related to Hilla

Comments

@OlliTietavainenVaadin
Copy link
Member

Describe your motivation

Related issue: #2788

In order to call Hilla endpoint methods, a CSRF token is needed. Currently, the CSRF token is available either from the document's meta header or a cookie and its use in the generated endpoints can be considered to be an implementation detail. If a Service Worker wants to call the endpoint method, the document is not available in its context and the invocation can't work; if the token is passed to the service worker, the endpoint call can still be made manually. However, right now, endpoint method calls from service workers require a lot of brittle boilerplate code.

Describe the solution you'd like

There's no one "best" approach, but an explicit framework-provided API would make service worker code more readable and less fragile.

For example, Hilla could create an indexedDb database that contains different configurations and values needed for a service worker to use endpoints. One of these values could be the CSRF token.

These values could be accessed via getter from e.g. hilla-sw-connector, which could contain a custom fetch implementation to include cookies and the CSRF token to abstract away the Hilla internal workings.

Pseudo-code example:

// ts
// Service Worker
import {CSRFToken, HillaFetch} from 'hilla-sw-connector'
console.log(typeof CSRToken); // string | undefined
// Hilla's fetch override
HillaFetch("EndpointPath")
HillaFetch("EndpointPath", options)
// The public api and usage could be identical to normal fetch
// https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch

Hilla side
A configuration setting could be used to tell Hilla to include hilla-sw-connector logic in the application.
This could be e.g. injected into index.html

Describe alternatives you've considered

Alternative: modify message object so that a service worker's message listener could access CSRF token, endpoint method path, and possibly more properties.

Then provide a utility for determining that message is coming from Hilla

// service worker
self.addEventListener('message', async (event) => {
  if (isHillaClientEvent(event)) {
   let token = event.hilla.csrfToken; // ...
  }
}

or

// service worker
HillaSwUtil.waitForToken( token => {
  // do things with token
});

Additional context

No response

@platosha
Copy link
Contributor

Let's rather aim at enabling the actual endpoint calls instead of low-level wrappers such as HillaFetch. The CSRF token should optimally be automatically provided, and not required from the user for calling the Hilla endpoints.

@krissvaa
Copy link
Contributor

After fixing #2867 we could introduce CSRF headers to the worker context just after the Service Worker registration by reading them from initial load cookies.
This could be done by adding to the generated index.tsx functionality for acquiring CSRF headers from cookies (as the Service worker doesn't have direct access to DOM and cookies) and passing the correct header to SW.

if ("serviceWorker" in navigator) {
    navigator.serviceWorker.ready.then((registration) => {
        //getting headers with the help of CSRFUtils.js from hilla-frontend
        const headers = getCsrfTokenHeadersForEndpointRequest(document); 
        registration.active.postMessage({ csrfHeaders: [] });
    });
}

In the generated sw.ts we would add a listener for receiving headers

let csrfHeaders;
addEventListener('message', (event) => {
    if (event.data && event.data.csrfHeaders) {
        csrfHeaders = event.data.csrfHeaders;

        //@ts-ignore
        self.Vaadin = self.Vaadin || {};
        //@ts-ignore
        self.Vaadin.csrfHeaders = csrfHeaders;
    }
});

In the Connect.ts could use SW CSRF headers instead of the usual DOM cookie headers if the SW has added them.
const csrfHeaders = $wnd.Vaadin.csrfHeaders ?? getCsrfTokenHeadersForEndpointRequest(document);

An enhancement would be to add an event or callback so users could call endpoints only after the CSRF tokens are acquired, like already proposed:

 HillaSwUtil.waitForToken( token => {
  // do things with token
});

@platosha
Copy link
Contributor

We can skip adding the callback API and make requests wait for the token internally.

@platosha
Copy link
Contributor

IT tests could use ChromeDeviceTest from Flow to enable service worker support.

@platosha
Copy link
Contributor

Depends on #2867

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request hilla Issues related to Hilla
Projects
None yet
Development

No branches or pull requests

3 participants