Add generic short code authentication system (#3078)
authorapophisnow <karlmohler@gmail.com>
Wed, 25 Feb 2026 17:57:51 +0000 (09:57 -0800)
committerGitHub <noreply@github.com>
Wed, 25 Feb 2026 17:57:51 +0000 (18:57 +0100)
commitd0e4114ea82350834e0c4e76c80002d6938b2b82
tree5bb574ccb69800ce6e586478059da98e9b09843d
parentc55e24cd75e361f56fb46708d29b61c71c7a60ca
Add generic short code authentication system (#3078)

* feat: add generic short code authentication system

Add a reusable short code authentication system that any provider can use
for QR code login, device pairing, or similar flows.

Changes:
- Add join_codes database table (schema v6)
- Add generate_join_code(user_id, provider_name, ...) method
- Add exchange_join_code() to convert codes to JWT tokens
- Add auth/code public API endpoint
- Add revoke_join_codes() for cleanup
- Update login.html to handle ?join= parameter
- Add provider_name parameter to JWT token encoding

Providers can implement short code auth flows like:

    code, expires = await auth.generate_join_code(
        user_id=my_user.user_id,
        provider_name="my_provider",
        expires_in_hours=24,
    )

The provider_name is stored in the join code and passed to the JWT token,
allowing providers to identify their authenticated sessions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Revise db migration

* test: add comprehensive tests for join code authentication

Add tests covering the short code authentication system:
- generate_join_code: basic functionality, invalid user handling
- exchange_join_code: success, case-insensitivity, expired codes,
  max_uses limits, unlimited uses, provider_name in JWT claims
- revoke_join_codes: per-user revocation, revoke all codes
- authenticate_with_join_code API: success and error cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update music_assistant/controllers/webserver/auth.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update music_assistant/helpers/resources/login.html

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update music_assistant/controllers/webserver/auth.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update music_assistant/controllers/webserver/auth.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* fix: Simplify join code schema

* chore: Update join code test

* fix: Fix revoke_join_codes() to use correct db count function

* fix: Simplify revoke_join_codes and add provider handling

* fix: Avoid useless rename

* fix: Handle rare collision edge case

* fix: Fix return type

* fix: Use named params

* fix: Rename prevents already defined error

* Add input validation to generate_join_code.

* Fix unhandled RunTimeError.

* Limit short codes to users with guest role only.

* Log security events.

* Rename endpoint and add endpoints to list and revoke codes.

* Make at least one parameter of revoke_join_codes required to prevent accidental deletion of all codes.

* Schedule cleanup of expired join codes once a day.

* Minor cleanup.

* Fixes for active source and current media with linked protocols

* Fix DSP not applying for AirPlay and Sendspin players (#3191)

* OpenSubsonic: Use server provided version tag if present (#3200)

* Fix use playerid for http profile

* ⬆️ Update music-assistant-frontend to 2.17.92 (#3203)

Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
* Expand PIN based auth in airplay 2 (#3165)

* add LG details

* Make pin based auth work in other devices

* remove reference to apple tv and macos in check

* remove unused constant and adjust airplay2 filter

* also apply pairing check to raop

* add unit test

* Revert MIN_SCHEMA_VERSION to maintain HA compatability.

* Add comments to schema version constants

* Fix some more issues with syncgroups

* Fix HEOS source switching back to Local Music after starting stream (#3206)

* Fix group mute for protocol-synced players (#3205)

* Handle HEAD requests on root route (#3204)

* Fix announcements typo

* Some small code quality changes to DLNA Provider

* Small simplification for GroupPlayer

* Fix Sonos S2 announcement 404 error on cloud queue context endpoint (#3208)

* Snapcast: Fixes for hard switching of group leaders (#3209)

* Gracefully skip files/folders with emoji names on SMB mounts (#3183)

* Add API to handle playback speed (#3198)

* Simplify can_group_with logic

* Airplay2-configurable-latency (#3210)

* Validate queue item ID in Sonos pause path (#3194)

* Add some additional guards to asyncprocess

* Add a bunch of extra error handling and logging for flow streams

* Properly cleanup stream buffers

* ⬆️ Update music-assistant-frontend to 2.17.93 (#3214)

Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
* Fix bluesound volume jumping back after volume_set.

* Speed-up core startup a bit

* More gracefully handle DLNA errors

* Lock set_members to avoid concurrent actions

* Fix issue with subprocess pips closing

* Fix ungroup command

* Add note in docstring

* Auto ungroup when trying to form syncgroup with already synced player

* Fix accessing player.state.synced_to

* Fix playback speed handling on queue item and not on queue

* Fix for _cleanup_player_memberships

* Fix race condition with enqueue_next_media on SyncGroup

* Fix some edge cases with AirPlay DACP commands

* Fix set_members with lock

* Fix player not available in HA at startup

* Fix fully_played should return boolean

* Auto translate commands directed at protocol player id to visible parent

* Some minor tweaks to handling prevent-playback of airplay

* Speedup core controller startup

* Pre-compile Python bytecode in Dockerimage for faster startup

* Speedup is_hass_supervisor check

* Fix _cleanup_player_memberships and _handle_set_members

* Fix player config not fully persisting

* ⬆️ Update music-assistant-frontend to 2.17.94 (#3218)

Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
* Bandcamp: validate login on init when credentials are configured (#3215)

Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Fix bluesound volume jumping back after volume_set.

* Use ImageType.THUMB for Bandcamp artwork images (#3212)

Bandcamp artwork is square, not landscape. All other music providers
in the codebase use THUMB for standard album and artist art.

Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Fix inverted track_number condition in Bandcamp converter (#3211)

The condition checked output.track_number instead of track.track_number,
meaning track numbers from the API were only applied when the output
already had a non-None default.

Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Clear internal HEOS queue before playing (#3219)

* Update Alexa player provider (#3167)

* Update Alexa player provider

* Remove redundant try catch

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Address PR comments

* Remove ActionUnavailble catches

* Remove extra catch alls and add _on_player_media_updated

* Remove catch all

* Bump AlexaPy

* Fix _upload_metadata when media is not available

---------

Co-authored-by: Sameer Alam <alams154@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Fix race condition in player register flow wrt config

* Fix select output protocol already in play_index to avoid race on flow mode

* Fail job on test failures

* Fix Radioparadise image URL (#3220)

The change to the documentation repo moved the images

* Fix flow mode determination

* Fix player tests

* Add genre icons and SVG handling to imageproxy (#3223)

* Add genre icons and SVG handling to imageproxy

* Cleanup

* ⬆️ Update music-assistant-frontend to 2.17.95 (#3222)

Co-authored-by: stvncode <25082266+stvncode@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
* Fix static members of sync group

* Fix last small issues with syncgroup

* Fix issue with clearing output protocol during track changes

* Use mass.call_later.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Marvin Schenkel <marvinschenkel@gmail.com>
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
Co-authored-by: Maxim Raznatovski <nda.mr43@gmail.com>
Co-authored-by: Eric Munson <eric@munsonfam.org>
Co-authored-by: music-assistant-machine <141749843+music-assistant-machine@users.noreply.github.com>
Co-authored-by: marcelveldt <6389780+marcelveldt@users.noreply.github.com>
Co-authored-by: hmonteiro <1819451+hmonteiro@users.noreply.github.com>
Co-authored-by: Tom Matheussen <13683094+Tommatheussen@users.noreply.github.com>
Co-authored-by: scyto <alex@alexbal.com>
Co-authored-by: David Bishop <teancom@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Mischa Siekmann <45062894+gnumpi@users.noreply.github.com>
Co-authored-by: OzGav <gavnosp@hotmail.com>
Co-authored-by: Andy Kelk <andy@andykelk.net>
Co-authored-by: Brad Keifer <15224368+bradkeifer@users.noreply.github.com>
Co-authored-by: Bob Butler <bob@robertjbutler.com>
Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Sameer Alam <31905246+alams154@users.noreply.github.com>
Co-authored-by: Sameer Alam <alams154@users.noreply.github.com>
Co-authored-by: stvncode <25082266+stvncode@users.noreply.github.com>
music_assistant/controllers/webserver/auth.py
music_assistant/helpers/jwt_auth.py
music_assistant/helpers/resources/login.html
tests/test_webserver_auth.py