nixamp.com as an OAuth 2.1 authorization server, and a watch party as a nixamp room - #127
Merged
Conversation
…ixamp room nixamp.com becomes an OAuth 2.1 authorization server, and a watch party on a site that connects through it becomes an ordinary nixamp live event with a room -- so the same party is joinable from the web app, the terminal, the desktop app, the television and an agent over MCP, without any of them learning anything about torrents. Which side is the authorization server was the first question. nixamp already keeps the accounts, the revocable tokens and the provider identities, and bittorrented.com keeps none of those, so nixamp is the AS and bittorrented is the client. src/oauth.ts stays what it was -- nixamp signing in WITH GitHub -- and src/oauth-server.ts is the other direction. It is 2.1 rather than 2.0, which is to say the things 2.0 left optional are not optional here: PKCE with S256 on every request from every client, public or confidential; redirect URIs matched exactly, with only a loopback port allowed to vary because a CLI cannot know its port before it listens; a code spent once, where a second use withdraws everything the first produced; refresh tokens that rotate, where a retired one presented again withdraws the whole family. There is no implicit grant and no password grant, and both are refused by name rather than shrugged at. RFC 8414 metadata says so at /.well-known/oauth-authorization-server. Access tokens are nixamp's own `nxa_` tokens with a client's name on them, which is what makes them revocable and what makes every existing /api/v1 route understand one with no change. An error that cannot be redirected is a page: bouncing a refusal to an unregistered redirect URI would make this an open redirector. The bridge itself (src/watch-party.ts) is deliberately thin. A bridged party is a live_events row like any other, plus one row saying which external party it is, where to watch it, and the second the host says everybody is at. That is what makes discovery, invitations, chat, layouts and /live/:slug work with no special case. Bridging is idempotent, because the client calls it every time somebody opens the party page. A watch link must be on the client's own site, read off the redirect URIs it registered rather than configured twice. Surfaces: web gets a Watch parties panel and a Connected apps list in the Account panel; `nixamp party` gets list/join/host/sync/end; `nixamp mcp` is a new stdio MCP server -- JSON-RPC on a pipe, no dependency -- offering those same five as tools to an agent. 545 tests pass, typecheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QuUkTrofSjQ15j79mRuy4f
After rebasing on #125 the INSERT carries kind, doors and the ticket fields, so the positional fake read status out of the wrong slot and every bridged party came back 500. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QuUkTrofSjQ15j79mRuy4f
ralyodio
force-pushed
the
feat/watch-party-oauth21
branch
from
September 12, 2026 11:29
0a3fb14 to
112dfe7
Compare
ralyodio
marked this pull request as ready for review
September 12, 2026 11:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
bittorrented.com has watch parties. nixamp has rooms, chat, invitations, a directory and five clients that can already open one. This makes them the same thing, with the identity link done by OAuth 2.1.
Which side is the authorization server
nixamp. It already keeps the accounts, the revocable tokens and the provider identities; bittorrented keeps none of those.
src/oauth.tsstays what it was -- nixamp signing in with GitHub -- and the newsrc/oauth-server.tsis the other direction: somebody signing in with nixamp.What "2.1" actually means here
The things OAuth 2.0 left optional are not optional:
plain./.well-known/oauth-authorization-server.Access tokens are nixamp's own
nxa_tokens with a client's name on them. That is what makes them revocable, and it is why every existing/api/v1route understands one with no change at all.An error that cannot be redirected is a page, not a bounce: sending a refusal to an unregistered redirect URI would make this an open redirector.
The bridge
src/watch-party.tsis deliberately thin. A bridged party is alive_eventsrow like any other, plus one row saying which external party it is, where to watch it, and the second the host says everybody is at. That is what makes discovery, invitations, chat, layouts and/live/:slugwork with no special case.Surfaces
nixamp party list / join / host / sync / endnixamp mcp-- a new stdio MCP server, JSON-RPC on a pipe, no dependency -- offering those same five as toolsThe film never crosses over. What nixamp carries is the room.
Testing
bun test test web/test: 545 pass, 1 skip, 0 fail.bun run typecheckclean (root + both web apps). 30 new tests acrosstest/oauth-server.test.tsandtest/party-cli.test.ts, including the S256 digest cross-checked against the value the bittorrented client's WebCrypto produces.Notes
NIXAMP_OAUTH_CLIENTSregisters a client beyond the built-inbittorrentedone;NIXAMP_OAUTH_BITTORRENTED=offremoves that one.🤖 Generated with Claude Code
https://claude.ai/code/session_01QuUkTrofSjQ15j79mRuy4f