Gateway: MusicKit login page + callback route #5

Closed
opened 2026-08-09 20:31:47 +00:00 by hermes · 1 comment
Owner

Context

Gateway service (see #18). This is the one interactive piece: a browser
flow that yields the Apple Music user token. The exact HTML to port already
exists in the plugin repo.

Task

Two routes in the FastAPI app:

  • GET /login — serve an HTML page that loads
    https://js-cdn.music.apple.com/musickit/v3/musickit.js, calls
    MusicKit.configure({developerToken: <fresh dev token>}), and on button
    click runs MusicKit.getInstance().authorize() then redirects to
    {GATEWAY_BASE_URL}/callback?media-user-token=....
    Port the page from beets-appleplaylists/beetsplug/appleplaylists/auth.py
    (_login_page). Embed the token with json.dumps.
  • GET /callback — parse media-user-token from the query string, store it
    via CredentialStore.save, render a plain success page ("Linked, you can
    close this tab"). Never log the query string (the token would leak
    into logs); the page must not echo the token either.

Deployment note (for the README, not code): the registered redirect URI on
the MusicKit Services ID must be the deployed https URL of /callback.

Acceptance criteria

  • Unit test (FastAPI TestClient): GET /login returns 200 with a page
    containing a MusicKit.configure call; GET /callback with
    ?media-user-token=abc stores "abc" and returns the success page; a
    callback without the parameter does not crash and stores nothing.
  • Log capture test: the token does not appear in captured logs.
## Context Gateway service (see #18). This is the one interactive piece: a browser flow that yields the Apple Music user token. The exact HTML to port already exists in the plugin repo. ## Task Two routes in the FastAPI app: - `GET /login` — serve an HTML page that loads `https://js-cdn.music.apple.com/musickit/v3/musickit.js`, calls `MusicKit.configure({developerToken: <fresh dev token>})`, and on button click runs `MusicKit.getInstance().authorize()` then redirects to `{GATEWAY_BASE_URL}/callback?media-user-token=...`. Port the page from `beets-appleplaylists/beetsplug/appleplaylists/auth.py` (`_login_page`). Embed the token with `json.dumps`. - `GET /callback` — parse `media-user-token` from the query string, store it via `CredentialStore.save`, render a plain success page ("Linked, you can close this tab"). **Never log the query string** (the token would leak into logs); the page must not echo the token either. Deployment note (for the README, not code): the registered redirect URI on the MusicKit Services ID must be the deployed https URL of `/callback`. ## Acceptance criteria - Unit test (FastAPI TestClient): GET /login returns 200 with a page containing a `MusicKit.configure` call; GET /callback with `?media-user-token=abc` stores "abc" and returns the success page; a callback without the parameter does not crash and stores nothing. - Log capture test: the token does not appear in captured logs.
Author
Owner

Done in coop/apple-music-gateway (commit c8db51c): GET /login serves the MusicKit JS login page (ported from the plugin's auth.py::_login_page; dev token and {GATEWAY_BASE_URL}/callback redirect embedded via json.dumps); GET /callback captures media-user-token (Query alias) into the CredentialStore and renders a success page that never echoes it. Query strings are scrubbed from the uvicorn access log (?[REDACTED]) so the token cannot leak via access logs either. README gained the deployment note (register the deployed https /callback as the MusicKit redirect URI). 6 route tests incl. log-capture; behaviour also verified with a real uvicorn run (0600 DB, redacted access log).

Done in `coop/apple-music-gateway` (commit `c8db51c`): `GET /login` serves the MusicKit JS login page (ported from the plugin's `auth.py::_login_page`; dev token and `{GATEWAY_BASE_URL}/callback` redirect embedded via `json.dumps`); `GET /callback` captures `media-user-token` (Query alias) into the CredentialStore and renders a success page that never echoes it. Query strings are scrubbed from the uvicorn access log (`?[REDACTED]`) so the token cannot leak via access logs either. README gained the deployment note (register the deployed https `/callback` as the MusicKit redirect URI). 6 route tests incl. log-capture; behaviour also verified with a real uvicorn run (0600 DB, redacted access log).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coop/beets-appleplaylists#5
No description provided.