Profiles and sign-in¶
Off until AUTH_TRUSTED_NETWORKS or AUTH_PROXY_SECRET is set: then everyone using Nessie is
someone, and the API turns away anyone who isn't.
- At home (a request from
AUTH_TRUSTED_NETWORKS): each device asks Who's listening? and remembers the answer. A profile can have a PIN (4 to 8 digits); a new PIN signs its other devices out, and so does Settings → Profiles → Sign out your other devices (a lost phone; admins can do it for anyone). The first profile is made here too, on a fresh start, and is an admin. Anyone on these networks can pick a profile without a PIN, admins' included: give admins a PIN if guests share your Wi-Fi. - Away, through a sign-in service (Authelia, Authentik, oauth2-proxy… behind Caddy, Traefik,
nginx): the proxy sends the signed-in user, and a shared secret so Nessie knows the header came
from it. Nessie trusts the secret, not the address: Docker and Tailscale can hide where a request
came from (through Tailscale, Docker shows its own gateway, e.g.
172.28.0.1). The user is the profile with their username, made the first time they come; their groups decide whether they're an admin (AUTH_ADMIN_GROUP), may make AI playlists (AUTH_AI_GROUP) or may request music from Lidarr (AUTH_REQUEST_GROUP). - Anywhere else: turned away.
What each may do: admins change Settings → Server, add and scan libraries, change pictures and details, and use Lidarr; making AI playlists needs admin or the AI permission (they cost money); everyone listens, searches, makes playlists and mixes, and imports playlists. Settings → Profiles adds and changes profiles (admins); anyone changes their own name and PIN, and signs their other devices out. The same person is the same profile at home and away: give their profile their sign-in username.
My libraries: each profile can mark the libraries that are its own (Settings → Libraries, One of mine). It's a preference, not a restriction: the sidebar shows those first and folds the others into Other libraries (one line each, opened in full while you're in one), and the lists that span libraries (Your music: Most played, Most played lately) use just them. None marked: all are. Those lists show in the sidebar only when they span two or more libraries: over one, they'd be that library's own Most played lists, which it shows already.
Listening history: a play counts for whoever played it: in the browser, the person using it;
on the server's speakers, whoever last started or queued music there. Most played, Most played
lately, the mixes (which favour your favourites), the play rules of custom mixes and AI playlists
("not played in 14 days"), and the Songs sorts by plays and last played are each person's own. An
artist's Popular songs and the classic UI (/v2/) count the whole household. Deleting a profile
keeps its plays in the household's counts. Plays from before profiles were switched on are no
one's: give them to someone with python -m app.cli give-plays USERNAME (in Docker,
docker exec <container> python -m app.cli give-plays USERNAME). Liked songs are each person's
too; ones liked with profiles off are the household's, and give-likes USERNAME gives them to
someone the same way.
Whose playlists and mixes are: a playlist you make (or import, copy or save from the queue or
an AI playlist) is yours, and so is a custom mix you save. The rest of this goes for both. Yours are shared: the household sees and plays them, and can Save a copy to
change, but only you change the original. Make one private (its ⋯ menu) and only you see it,
admins included. The household's playlists (ones from before profiles, and any given to it) are
everyone's to change. Admins look after the household's playlists but not its taste: they can
delete or give away anyone's they can see, not change them. The Playlists page shows all of them,
yours, or the ones shared with you; the Mixes page has Your mixes, then Shared mixes. A shared mix
still picks for whoever plays it: "not played in 2 weeks" means your plays when you play it.
Deleting a profile asks what happens to its playlists and mixes: the household's, someone
else's, or deleted. Those from before profiles are the household's; give some to their owner with
python -m app.cli give-playlists USERNAME and give-mixes USERNAME (each lists them to choose
from by number; name them, or --all, to skip the list). A playlist whose name they have already
becomes "Name (household)".
With Authelia and Caddy (in your Caddyfile; the secret also in Nessie's AUTH_PROXY_SECRET):
audio.example.com {
encode
route {
# Only the sign-in service says who's signed in, never the browser
request_header -Remote-User
request_header -Remote-Groups
request_header -Remote-Name
request_header -Remote-Email
forward_auth authelia:9091 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}
reverse_proxy nessie-server:8000 { # where the proxy reaches Nessie (e.g. its Tailscale name)
header_up X-Nessie-Proxy-Secret {$NESSIE_PROXY_SECRET}
}
}
}
and in Authelia, groups nessie-admins, nessie-ai and nessie-requests for whoever should have them. route keeps
the steps in that order. Authelia replaces those headers for someone signed in; removing them
first also covers a request it lets through without saying who it is (a bypass rule).
Keep the secret secret: with it, a request can say it's anyone, an admin included. Two more things help:
- Only the proxy should reach Nessie's port. Nessie can't check that itself when Docker hides
where requests come from. Through Tailscale, an ACL does it: tag the two machines and allow
only the proxy's to the port (
{"src": ["tag:vps"], "dst": ["tag:nessie"], "ip": ["tcp:8000"]}in the policy'sgrants, with no other rule reachingtag:nessieon 8000). Or a firewall rule on Nessie's machine, in Docker'sDOCKER-USERchain. - Test it: signed in,
curl -b "<your sign-in cookie>" -H "Remote-User: someone-else" https://audio.example.com/v1/meshould answer as you.
Other sign-in services name their headers differently:
| User | Name | Groups (separator) | |
|---|---|---|---|
| Authelia (default) | Remote-User |
Remote-Name |
Remote-Groups (,) |
| Authentik | X-authentik-username |
X-authentik-name |
X-authentik-groups (\|) |
| oauth2-proxy | X-Forwarded-User |
X-Forwarded-Preferred-Username |
X-Forwarded-Groups (,) |
| Tailscale Serve | Tailscale-User-Login |
Tailscale-User-Name |
(none: set admins in Nessie) |