Collab token issuance and connection authentication #34
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#34
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Connections must be authorized by the API — the collab server never talks to session cookies (ADR 0003/0007).
Scope
API:
GET /pages/:id/collab-tokenreturns a JWT (≤60 s TTL, claims: userId, pageId, mode rw/ro) signed with the shared env key, using the interim access service (real permissions land in #53). Collab:onAuthenticateverifies signature/expiry/pageId match, stores user context on the connection, enforcesroby dropping inbound document messages. Shared claim schema inpackages/shared.Acceptance criteria
roconnections receive updates but their document writes are discarded server-side (test with two clients)Technical notes
Dependencies
Depends on #23, #33.
Size: ~1 day
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.▎ Verified on Test and Int (commit
d4ebcfc, pipeline green — all CI + CD jobs incl. Int promotion).▎
▎ - Both dorfteich-{test,int}-collab-1 and -api-1 are Up (healthy) after restarting with the new shared COLLAB_TOKEN_SECRET.
▎ - GET /pages/:id/collab-token returns 401 unauthenticated (route deployed + guarded).
▎ - Full authenticated loop on Test (fixture-user → create page → token): 200, mode: rw, expiresInSeconds: 60, a valid 3-part HS256 JWT.
▎
▎ Implementation notes:
▎ - The token is the only JWT in the system (ADR 0007), HS256 via node:crypto. Sign/verify live in packages/shared/src/token-crypto.ts behind the @dorfteich/shared/token-crypto subpath export (with typesVersions for the api's node10 resolution) so the web bundle never pulls in node:crypto; browser-safe schemas/types stay in the barrel.
▎ - collab onAuthenticate verifies signature/expiry, requires claims.pageId === documentName, and enforces ro via Hocuspocus' connectionConfig.readOnly. Read-only enforcement is covered by a two-client integration test (@hocuspocus/provider).
▎ - COLLAB_TOKEN_SECRET is shared by api and collab (must match); set per stage in each .env, required in the stage compose.
Reposting the verification note cleanly under the model account — the earlier comment was pasted manually and picked up formatting artifacts (leading
▎quote bars).Verified on Test and Int (commit
d4ebcfc, pipeline green — all CI + CD jobs incl. Int promotion).dorfteich-{test,int}-collab-1and-api-1are Up (healthy) after restarting with the new sharedCOLLAB_TOKEN_SECRET.GET /pages/:id/collab-tokenreturns 401 unauthenticated (route deployed + guarded).mode: rw,expiresInSeconds: 60, a valid 3-part HS256 JWT.Implementation notes:
node:crypto. Sign/verify live inpackages/shared/src/token-crypto.tsbehind the@dorfteich/shared/token-cryptosubpath export (withtypesVersionsfor the api's node10 resolution) so the web bundle never pulls innode:crypto; browser-safe schemas/types stay in the barrel.onAuthenticateverifies signature/expiry, requiresclaims.pageId === documentName, and enforcesrovia Hocuspocus'connectionConfig.readOnly. Read-only enforcement is covered by a two-client integration test (@hocuspocus/provider).COLLAB_TOKEN_SECRETis shared by api and collab (must match); set per stage in each.env, required in the stage compose.