Skip to content

[Feature] Managed accounts and server-side PIN #328

Open

Description

@benklop

What problem does this solve?

Families sharing one TV have no way to say "these accounts belong together", and the PIN
the clients offer is stored per device:

  • Every client's sign-in PIN is local to the device. A PIN set on one TV does nothing on
    another, and the clients can't offer "admins must have a PIN" in any enforceable way.
  • The stored value is an unsalted SHA-256 of a 4-digit PIN, and the client-side lockout
    is reset by clearing app data. The plugin has no PIN storage or route today.
  • The user picker shows every public user on the server. On a server hosting more than one
    family, each TV shows everyone.

Proposed solution

All of it is additive and optional. Clients keep working unchanged without it, and the
clients must stay fully usable when the plugin is absent or unreachable.

  1. Managed accounts. Each user gets a managedBy list of administrator user IDs, stored
    in the plugin configuration. It is a list so a child with parents in separate homes can
    be managed by both.
    • PUT /Moonfin/Users/{id}/ManagedBy (admin) sets the list.
    • GET /Moonfin/Managed (any signed-in user) returns the users the caller manages as
      {id, name, imageTag}, so a client can filter its user picker.
    • A "Managed by" picker per user on the existing plugin config page.
  2. Server-side PIN. The plugin stores a salted, slow hash per user and verifies it, so
    clients stop comparing hashes and can't be defeated by reading the synced value.
    • GET /Moonfin/Pin returns { enabled } only, never a hash. PINs are exactly 4 digits,
      matching what the clients accept today.
    • PUT /Moonfin/Pin sets or changes it (requires the current PIN when one exists).
    • POST /Moonfin/Pin/Verify checks an entry, with server-side rate limiting and lockout.
    • DELETE /Moonfin/Pin removes it (current PIN, or an admin).
    • An admin-reset path for forgotten PINs.
    • The config page lists administrators who have no PIN, so setting one doesn't depend
      on a client prompt. Clients only prompt when no server-side PIN is available.

Settings stay additive: new properties are nullable and typed the way clients send them,
per the settings-profile rule in CONTRIBUTING.

Area

Admin defaults / config page

Server

Jellyfin

Client impact

Needs matching client work in Moonfin-Core (Moonfin-Client/Moonfin-Core#1912), Smart-TV (Moonfin-Client/Smart-TV#541) and Roku (Moonfin-Client/Roku#310). Clients keep working without the plugin.

Alternatives considered

  • Sync the hash through the existing settings profile. Needs every client to produce
    the identical hash, which is hard with a salted scheme across four toolchains, and still
    leaves the hash readable.
  • Named household groups. More to build and name, with no benefit over a managed-by list.

Additional context

  • Companion client proposals: Moonfin-Core [Feature] Family features: admin PIN, QR approval, managed accounts, time limits Moonfin-Core#1912, Smart-TV [Feature] Family features: server-backed PIN, QR approval, managed accounts, time limits Smart-TV#541, Roku [Feature] Family features: server-backed PIN, managed accounts, time limits Roku#310.
  • Clients detect the plugin with /Moonfin/Ping and fall back to today's local behavior.
    If the plugin is unreachable at the PIN gate they fall back to a locally cached verifier
    rather than locking the family out (fail-open, by design).
  • Migration: when a plugin appears for a device with a local PIN, the next successful local
    verify uploads what the user typed, since the client only holds a hash.
  • Emby is not changed. All new code lives under Jellyfin/. I won't touch shared/
    or Emby/, because the Emby project compiles shared/*.cs and I have no Emby server to
    test on. Clients must treat these routes as absent on Emby (they already degrade when
    the plugin lacks a feature). If you want Emby parity later, that is a separate change
    that needs someone with an Emby server to test.
  • I'll build and maintain both parts, as separate PRs (managed accounts, PIN)
    once the shape is OK, and I'll run the Jellyfin and Emby test projects to confirm
    nothing regressed.
  • I used an AI assistant (Claude) to help research and draft this proposal and will say so
    on any PR. I'm the one who will build, test (against my own Jellyfin server) and answer for the change.

Activity

  1. github-actions commented on Oct 18, 2026

    @github-actions

    Thanks for the report, @benklop.

    Before anyone can pick this up it needs a little more from you, so it has been labelled Missing Template.

    This issue skipped the issue form

    It was opened without one of the forms, so the fields that say which version, platform and setup this involves are all missing.

    The forms also decide how an issue gets labelled and routed. Skipping the form means nobody was prompted for the one thing the report actually needs.

    Please open a fresh one from New issue and pick the form that fits, then this can be closed as a duplicate. If you would rather not start over, paste the form's answers into a comment below and they will be picked up.

    • Bug: Server / Plugin for the plugin or the server side, which needs a screenshot
    • Bug: Settings Sync for settings not carrying between clients, which needs a screenshot
    • Feature request for something new

    Each label comes off automatically once that piece is sorted.

  2. benklop commented on Oct 18, 2026

    @benklop
    Author

    @RadicalMuffinMan I have a handful of features I had built on the previous android TV app and have been using on my own fork for a while. I'd like to get back to using vanilla moonfin, so i'm working on porting them to the new client apps and server plugin. For the plugin itself there are only 2 things:

    • a way to sync the pin so when you install an app on a new TV, it already has the PINs set
    • a way to log in to jellyfin with a specific account, and have specific additional accounts automatically visible on that device. The idea is to have an experience similar to most streaming services.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions