Skip to content

Instantly share code, notes, and snippets.

@fsubal
Last active June 17, 2025 00:57
Show Gist options
  • Select an option

  • Save fsubal/8280365f54f5b262aef9d4bedf3ed775 to your computer and use it in GitHub Desktop.

Select an option

Save fsubal/8280365f54f5b262aef9d4bedf3ed775 to your computer and use it in GitHub Desktop.
/// <reference lib="webworker" />
/**
* Rails の CSRF トークンを取得し、それを使ってリクエストを送信する
*
* ワーカースクリプトで動作する
*
* ワーカースクリプトの場合、メインスクリプトからメッセージを送信して CSRF トークンを更新する
* メインスクリプトからメッセージを送信して CSRF トークンを更新する
* メインスクリプトからメッセージを送信して CSRF トークンを更新する
*/
class RailsCsrf {
#csrfToken?: string
#tokenSourceUrl: URL
constructor(tokenSourceUrl: URL) {
this.#tokenSourceUrl = tokenSourceUrl;
}
async refresh() {
const response = await fetch(this.#tokenSourceUrl, {
credentials: 'include',
});
const token = response.headers.get('X-CSRF-TOKEN');
if (token) {
this.#csrfToken = token;
}
}
async onFetch(request: Request) {
const response = await this.#proxyFetch(request);
if (response.status === 403) {
return this.refresh().then(() => this.#proxyFetch(request.clone()));
}
return response;
}
async #proxyFetch(request: Request) {
if (this.#csrfToken == null) {
throw new TypeError('CSRF token not loaded');
}
request.headers.set('X-CSRF-Token', this.#csrfToken);
return fetch(request);
}
}
const { origin, searchParams } = self.location;
const tokenSourceUrl = new URL(searchParams.get('token_source_url') ?? '', origin);
const railsCsrf = new RailsCsrf(tokenSourceUrl);
// 初回トークン取得
self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(railsCsrf.refresh());
});
self.addEventListener('message', (event: MessageEvent) => {
if (event.data === 'refresh-csrf-token') {
railsCsrf.refresh();
}
});
self.addEventListener('fetch', (event: FetchEvent) => {
const { request } = event;
const { method } = request;
if (method === 'GET' || method === 'HEAD') {
return;
}
event.respondWith(railsCsrf.onFetch(request));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment