A decentralized music tracking and discovery platform built on AT Protocol 🎵 rocksky.app

fix(web,web-mobile): let music-service OAuth callbacks bypass the service worker #44

Merged byjp.me
targeting main from byjp.me/rocksky:fix/pwa-oauth-callback-denylist
Merged opened by and assigned to byjp.me
targeting main from byjp.me/rocksky:fix/pwa-oauth-callback-denylist

Connecting a Spotify account is currently impossible from any browser that has the Rocksky service worker registered. Returning from Spotify's consent screen lands on https://rocksky.app/spotify/callback?code=…&state=… and renders a bare Not Found, with the URL unchanged.

Root cause #

The PWA service worker sets navigateFallback: "/index.html", which answers every navigation from the precached app shell unless the path appears in navigateFallbackDenylist. /spotify/callback was never added to that list, so:

  1. The service worker intercepts the top-level navigation back from Spotify.
  2. The path isn't denylisted, so it's answered from the cached shell.
  3. The request never leaves the browser — neither app-proxy nor the API sees it.
  4. The router has no /spotify/callback route, so it shows "Not Found".

(This looks to have been introduced in f6a24d01, 2026-07-19, about four weeks ago.)

Dropbox and Google Drive have the same gap. The existing /^\/oauth/ entry is anchored at the start of the path, so it never matches /dropbox/oauth/callback or /googledrive/oauth/callback.

Fix #

Add redirect URIs to navigateFallbackDenylist:

/^\/spotify\//,
/^\/dropbox\/oauth\//,
/^\/googledrive\/oauth\//,

/spotify/ is denylisted as a whole prefix:, but Dropbox and Google Drive are deliberately scoped to their /oauth/ subpath, because /dropbox, /dropbox/$id, /googledrive and /googledrive/$id are real SPA pages (a blanket /^\/dropbox\// would break them offline).

Workaround until this ships #

Add api. to the start of the "Not found" URL (ie. it becomes https://api.rocksky.app/spotify/callback?code=…&state=…). The server uses a fixed SPOTIFY_REDIRECT_URI for the token exchange regardless of which host receives the callback, so Spotify's exact-match check still passes.

(Note: I avoided merging the service worker denylist and app-proxy's route list; tough their drift is potentially the cause of the issue here — you may wish to have one driven from the other to prevent this kind of failure in the future!)

Commits 1

fix(web,web-mobile): let music-service OAuth callbacks bypass the service worker