navidrome/server/nativeapi
Deluan Quintão 59810c3d59
feat(jellyfin): non-expiring, audience-scoped tokens revocable by password change (#6013)
* feat(auth): add per-user token_epoch column and bump method

* feat(auth): add aud and ep claims, omitted when zero

* feat(auth): add CreateAPIToken for non-expiring, audience-scoped tokens

* feat(auth): add CheckClaims for epoch and audience validation

* feat(jellyfin): issue non-expiring, jellyfin-scoped access tokens

* fix(subsonic): reject API-scoped and revoked tokens on the jwt path

* fix(server): reject API-scoped and revoked tokens on the native API

* fix(server): pin the token-subject guard and stop leaking test config

Adds a regression spec for the DevAutoLogin/ExtAuth guard in
tokenAllowed, switches its comparison to case-insensitive to match
the user lookup's own COLLATE NOCASE semantics, and restores Subsonic
JWT test config after each spec instead of leaking SessionTimeout.

* feat(request): add a token epoch holder for handler-to-middleware signalling

* refactor(server): write the refreshed JWT header after the handler runs

* feat(auth): revoke all tokens for a user when their password changes

* fix(server): restore Unwrap on the JWT refresh writer so SSE write deadlines apply

* test(auth): pin that non-session tokens reject API access tokens

* test(jellyfin): pin token scoping and epoch revocation end to end

Exercises auth.CreateAPIToken and CheckClaims against the real Jellyfin
router and SQLite DB: the minted token has no exp and is aud-scoped to
jellyfin, and bumping token_epoch through the real UserRepository revokes
an already-issued token on the next protected request.

* test(nativeapi): pin the token-epoch handoff through a real password-change request

Drive a self password change through the real Authenticator/JWTRefresher
chain and a real SQLite-backed userRepository, so the epoch handoff between
Put and the refreshed-token writer is verified end to end, not as two
separately-tested halves. Also fix tokenAllowed to read the enriched ctx it
was given instead of r.Context(), so its warning log carries the username.

* refactor(server): drop tokenAllowed's now-unused request parameter

Finding-2 already moved every use to ctx; r was dead weight. Also note
in the new nativeapi test why it must stay the package's only real-DB
spec: db.Db() is a process-wide singleton its cleanup closes for good.

* refactor(auth): remove duplication in claim decoding and token minting

* refactor(auth): group aud with the standard JWT claims

* refactor(auth): read aud with the standard-claim accessor pattern

* fix(log): redact every api_key spelling the Jellyfin API accepts

* fix(auth): bind session tokens to the user id, not just the username

* fix(auth): return the token epoch from the same atomic increment

* fix(auth): bump the token epoch in the same statement as the password write

* chore(auth): trim comments to the why-only budget
2026-08-22 20:36:24 -04:00
..
artists.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
artwork.go feat(cli): add an artwork command group for diagnosing and re-driving artwork (#5957) 2026-08-14 21:07:56 -04:00
artwork_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
config.go refactor(conf): replace eager dir creation with lazy Dir type (#5495) 2026-05-13 17:44:22 -03:00
config_test.go feat(sharing): enable sharing by default (#5714) 2026-07-04 19:55:34 -04:00
image_upload.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
inspect.go chore(deps): bump golangci-lint to v2.10.0 and suppress new gosec false positives 2026-02-17 09:28:42 -05:00
library.go fix: album statistics not updating after deleting missing files (#4668) 2025-11-08 20:11:00 -05:00
library_test.go feat(sharing): enable sharing by default (#5714) 2026-07-04 19:55:34 -04:00
missing.go refactor(server): drop redundant error return from req.Strings parsing (#5812) 2026-07-18 19:30:04 -04:00
native_api.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
native_api_song_test.go feat(sharing): enable sharing by default (#5714) 2026-07-04 19:55:34 -04:00
native_api_suite_test.go Rename log.LevelCritical to log.LevelFatal 2022-12-21 14:53:36 -05:00
playlists.go fix(playlist): block track edits on synced playlists across all APIs (#5984) 2026-08-19 08:47:53 -04:00
playlists_test.go fix(playlist): block track edits on synced playlists across all APIs (#5984) 2026-08-19 08:47:53 -04:00
plugin.go feat(plugins): allow mounting library directories as read-write (#5122) 2026-02-28 10:59:13 -05:00
plugin_test.go feat(sharing): enable sharing by default (#5714) 2026-07-04 19:55:34 -04:00
queue.go chore(deps): bump golangci-lint to v2.10.0 and suppress new gosec false positives 2026-02-17 09:28:42 -05:00
queue_test.go refactor: multiple syntax updates for Go 1.26 2026-05-19 18:02:36 -03:00
radios.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
translations.go feat(ui): show translation completion percentage in the language selector (#5979) 2026-08-18 09:32:26 -04:00
translations_test.go test: unskip path-separator tests on Windows (#5381) (#5916) 2026-08-19 11:50:32 -04:00
user_password_token_refresh_test.go feat(jellyfin): non-expiring, audience-scoped tokens revocable by password change (#6013) 2026-08-22 20:36:24 -04:00