Tauri capabilities are a real boundary, not documentation. Permissions are
granted per window label in src-tauri/capabilities/; the default set covers
only version, window management, updater, clipboard text, the
library cache (fixed Rust commands, no SQL), settings, pins, the saved
playback session (fixed load/save/delete commands, size- and item-capped),
logging, window effects, the Windows media session, and opening the diagnostic
window. There is no shell, dialog, notification, process, or
global-shortcut plugin, no arbitrary command execution, and remote Apple
origins get no filesystem/shell/updater access.
The tray icon is Tauri's core tray-icon feature, built in Rust. Its menu
emits the same windows-media-control event as the Windows media buttons and
grants the webview no additional permissions.
The Phase 0 music-diagnostic window loads https://music.apple.com/ with an
empty permission list, local: false, and remote URL scope limited to that
origin. It has zero Tauri commands, and its navigation is limited to
https://*.apple.com because it shares the app's cookies. Do not scrape
Apple's DOM, inject scripts into that page, or add privileges to that
capability unless a later gate failure documents a narrowly scoped need.
The main window refuses top-level navigation to anything but the bundled app
(tauri.localhost, or the dev server in debug builds). A popup or a stray link
can therefore never turn the privileged window into a remote page.
MusicKit authorize() uses window.open to authorize.music.apple.com. Tauri
2 denies webview popups unless on_new_window allows them. The main window is
created from Rust (create: false) so that handler can allow only Apple auth
hosts and about:blank. Allowed popups use WebView2's default window (no Tauri
IPC). Never log the authorize URL; the query string is the developer JWT.
Content Security Policy in src-tauri/tauri.conf.json limits scripts to the
exact js-cdn.music.apple.com host and uses an exact host for the
authorization frame, plus provisional https://*.apple.com and
https://*.mzstatic.com subdomain wildcards for image, connect, and media
traffic. Narrowing scripts to the /musickit/ path waits on a signed-in
playback check, because MusicKit may load further code from that host during
playback. The observed host list is still pending;
docs/MUSICKIT_NETWORK_SURFACE.md records that status and the provisional
surface. Reconcile those entries after a fresh Phase 0 export. Never broaden
CSP or capabilities to make a bug disappear; document the required origin
first.
- There are two token classes: the developer token (signed from your Media Services private key) and the Music User Token (the subscriber's, managed by MusicKit). Keep them conceptually separate everywhere.
- Never ship the
.p8private key in the app, installer, repo, bundle, binary, or CI log. Only the signed developer JWT is shipped. MUSICKIT_DEVELOPER_TOKENlives in.env(gitignored; copy.env.example→.env).npm run phase0:mint-tokenmints it fromMUSICKIT_TEAM_ID,MUSICKIT_KEY_ID, and an absoluteMUSICKIT_P8_PATHoutside the repo; it never prints the JWT or.p8.- Debug builds read the token from the process environment at runtime
(
dotenv -e .env -- tauri dev). - Release builds embed the token at compile time.
src-tauri/build.rsreads it from the release machine's.envand validates it withsrc-tauri/src/token_policy.rs(ES256 JWT, integerexp, at least 30 days left), or fails the build. At runtimeget_developer_tokenserves only the embedded token, never the user's environment, and reports an expired token as "install the latest update".release-preflight.jsruns the same check before a draft release exists. - The embedded JWT can be extracted from the binary, as with any MusicKit web app. Its lifetime is the exposure window: Apple caps it at 6 months, so a new release must ship before the embedded token expires.
- Release tokens carry no
originclaim. Apple accepts an origin-restricted token for catalog requests but refuses library (/v1/me) requests, even fromhttp://tauri.localhost, so 0.1.0 cannot load anyone's library.build.rsandrelease:preflightreject one, and the native E2E checks the embedded token has none. The claim only limited browsers anyway: a native client can send anyOriginheader. - Mint on a machine that holds the
.p8, and copy only the JWT to the release machine. ARLET_SKIP_MUSICKIT_TOKEN=1builds a release binary without a token for unpublished CI smoke builds only.tauri-windows-build.jsand the release preflight refuse it.
Auth data is toxic: Apple passwords, Music User Tokens, developer private
keys, cookies, full Authorization headers, the updater private key, and
token-service bearer values are never logged. Both the Rust logger
(src-tauri/src/logging.rs) and the frontend (src/platform/redact.ts)
redact JWT-shaped values and values labelled by a token key
(Music-User-Token, media-user-token, musicUserToken, developerToken).
The frontend also redacts the exact developer and Music User Token values
once MusicKit has produced them. Request logs record method/path/status/
duration only. The Rust redactor has unit tests; the native E2E checks that a
Music User Token never reaches the log file.
The log file (arlet.log in the local app data folder) is opt-in: it is
written only while Settings › Debug Mode is on, which is off by default. The
in-memory recent log that Copy diagnostics report uses works either way and
never leaves the machine unless the user pastes it. One exception is written
regardless of Debug Mode: a native crash, or the main window failing to open,
appends a single redacted [native] line, because nothing else would record
it.
MusicKit JS loads from Apple's CDN at runtime and runs in the main webview, so
it can call every command the main window is granted. It cannot be pinned with
Subresource Integrity because Apple updates it in place. The mitigation is to
keep the grant small: the webview has no generic SQL, filesystem, shell,
dialog, notification, or process access, and the library cache is reachable
only through fixed, size-bounded commands (src-tauri/src/library_cache.rs).
Clipboard read remains for paste in the context menu. Window permissions are
the ones the custom title bar uses, plus set-size for the native E2E.
Tauri's isolation pattern is the next step if the grant ever needs to grow.
Now-playing artwork is fetched by Windows itself for the media overlay, so
only *.mzstatic.com and *.apple.com artwork URLs are passed on; any other
host would learn the user's IP address.
Signing out stops playback, revokes MusicKit authorization, clears the SQLite library cache, and deletes the local pinned-playlist file, so the next Apple ID on the same Windows account starts clean.
Windows Authenticode (Azure Artifact Signing), Tauri updater signatures, and
GPG detached signatures are three independent mechanisms; one is never
accepted as proof of another. See docs/RELEASE.md.
Do not file public issues for suspected vulnerabilities. Open a private security advisory on the GitHub repository so the issue can be fixed before disclosure.