One Participant Screen Share Publish Permission With 7-Recipient Fan-Out Control

# webrtc# screen# backend
One Participant Screen Share Publish Permission With 7-Recipient Fan-Out ControlMagnusNilsson2124

Short answer: Grant the presenter role on the server, bind it to one session and one participant, and...

Short answer: Grant the presenter role on the server, bind it to one session and one participant, and require a fresh browser capture action before any screen track is published. For a healthtech room with one clinician and seven viewers, the least complex design is one active screen-share grant, one authoritative owner record, and a deny-by-default check at signaling time. The browser still controls whether capture begins; the backend controls whose captured track the room will accept.

That distinction matters. A server cannot silently confer the user's browser permission to capture a display. WebRTC defines media transport, while display selection and user consent remain client-side concerns. Treating an application role as browser consent creates a security promise the system cannot keep.

The dominant runtime term is media fan-out, not the grant row. If an assumed screen stream averages 2.5 Mbit/s and seven remote participants receive it through a forwarding topology, budget against 2.5 x 7 = 17.5 Mbit/s of outbound forwarded media while the share is active, before protocol overhead and retransmission. This is a capacity-planning example, not a universal bitrate. Measure the actual encoded rate in production.

How should NodeJS grant one participant screen share publish permission?

It authorizes the application to accept a screen track from a specific participant in a specific room for a bounded interval. It does not authorize camera publication, microphone publication, a second screen track, another room, or another participant using a copied message. It also does not bypass the browser's capture prompt.

Keep three decisions separate:

  1. The backend decides who may attempt screen publication.
  2. The browser asks the user to select and approve a display surface.
  3. The media control plane accepts or rejects the resulting screen track for that room.

This split closes a common gap in notification-like systems: accepting delivery is not the same as granting authority to originate it. Health data makes that distinction especially important. A waiting-room attendee should not become a presenter because a UI button was hidden incorrectly or because an old signaling message was replayed.

Default to denial.

The grant should contain a room identifier, participant identifier, purpose limited to screen publication, issue time, expiry time, and a unique grant identifier. Sign it or keep it server-side behind an opaque reference. In either design, validate the current room membership and grant state when publication is requested; a role embedded in a long-lived connection should not remain authoritative forever.

Model the grant as a small state machine

The application needs an atomic transition, not a collection of loosely related booleans. available -> issued -> consumed is enough for a one-use grant. Expiry and revocation can terminate either an issued grant or an active publication.

The following Python expresses the policy independently of transport. An Express handler can apply the same checks before forwarding a publish request to the signaling layer. The important part is the compare-and-set behavior around consume, which must be implemented atomically in the real datastore.

from dataclasses import dataclass
from datetime import datetime, timezone


@dataclass
class ScreenGrant:
    grant_id: str
    room_id: str
    participant_id: str
    expires_at: datetime
    consumed: bool = False
    revoked: bool = False

    def consume(self, room_id: str, participant_id: str) -> None:
        now = datetime.now(timezone.utc)
        if self.revoked or self.consumed or now >= self.expires_at:
            raise PermissionError("screen-share grant is inactive")
        if room_id != self.room_id or participant_id != self.participant_id:
            raise PermissionError("screen-share grant does not match")
        self.consumed = True
Enter fullscreen mode Exit fullscreen mode

Do not trust participant_id from the request body. Derive it from the authenticated connection or session, then compare it with the grant. Likewise, derive the room membership from server state. Otherwise, the check looks precise while the caller still chooses both sides of the comparison.

Issuance must also serialize on the room. Two moderators can click at nearly the same moment; without a uniqueness constraint or transactional lock, both requests may observe "no presenter" and issue valid grants. Use one active-owner record keyed by room, and make replacement explicit. Rejecting the second request is easier to reason about than silently preempting a clinician who is already presenting.

Race it deliberately. In one test, hold the datastore transaction open after moderator A reads the empty owner record, let moderator B reach the same read, then release both writes together. The test passes only when one write wins and the other receives a conflict; two successful grant responses expose a broken uniqueness boundary. Repeat the case with the same target participant because deduplication by participant can hide the room-level race, then repeat it with two different targets to verify that the constraint actually belongs to the room owner record.

The same discipline applies after publication starts. On disconnect, do not immediately hand the role to someone else if the transport can reconnect. Mark the owner as temporarily detached, allow a short policy-defined recovery interval, and require the reconnecting identity to match. The interval is a product and risk decision, so there is no honest universal number. A clinical handoff workflow may choose immediate revocation instead.

Make signaling enforce the decision twice

The first enforcement point is the application endpoint that issues the grant. In an Express application, middleware should authenticate the moderator, load current room membership, verify that the target participant is eligible, and atomically create the grant. Return only the narrow grant reference and its expiry. Do not return a general publisher role.

The second point is where signaling announces or attaches a screen track. Check the grant again there and consume it. Client-side labels such as screen, display, or presenter are hints, not authority. The server-side media path should associate the accepted publication with the authenticated participant and the active room owner.

One check is insufficient. Issuance and use are separated by time, during which the participant may leave the appointment, the moderator may revoke access, or the grant may expire. Revalidation handles those edges without asking the UI to maintain security state.

Replays happen.

The browser sequence stays intentionally ordinary: the user clicks Share, the page requests display capture, and only after capture succeeds does the client send its grant reference with the signaling request. If the user cancels the picker, no track should be announced and the grant may remain unused until expiry or be explicitly released according to policy. Never claim that receiving the grant means the screen is already being captured.

Fast failure helps here. Return a stable denial category to the client, but keep sensitive details out of the message shown to other room members. The presenter needs to distinguish expired authorization from a local capture cancellation; viewers usually need only a neutral "presentation ended" state.

Delivery guarantees determine the fan-out design

Screen sharing is live state, not a durable notification. A viewer who joins late needs the current publisher and current track description, not every historical publish event. Model the owner record as authoritative state and signaling messages as hints that tell clients to refresh it.

This changes the delivery target. Exactly-once delivery is unnecessary for hints and is generally a misleading goal across reconnects. Make messages idempotent by including a monotonically increasing room revision. A client applies a state update only when its revision is newer than the one already rendered. Duplicate delivery then becomes harmless, and a missed event can be repaired with a current-state read.

For the seven-recipient example, send one logical state transition and fan it out to all connected viewers. Acknowledgements can establish that each connection received the transition, but they do not prove that video rendered or remained readable. Observe those outcomes separately through media statistics and client state.

I would retain compact authorization and ownership events rather than signaling payloads or media: grant issued, grant consumed, owner changed, grant revoked, and share ended. Each event needs the actor, subject, room, server timestamp, revision, and reason category. Avoid screen titles, captured pixels, free-form clinical text, and raw tokens. Those fields add exposure without improving the authorization proof.

The operational table is small enough to scan:

Failure Required behavior Evidence to retain
Duplicate publish request Consume once; reject later attempts Grant ID and room revision
Viewer misses an update Read current owner state Resync count and revision gap
Presenter reconnects Rebind only after identity and policy checks Connection change and decision
Moderator revokes access Stop accepting the publication and advance revision Actor, subject, reason category
Room ends Revoke the grant and clear active ownership Terminal room revision

Test these as races, not only as happy-path endpoint tests. Run concurrent issuance attempts for two participants, replay the same grant, revoke between capture and publish, reconnect under a different identity, and deliver room revisions out of order. Also test a viewer that is offline for the entire share. It should learn the final current state rather than replaying a stale presentation.

Keep less data and accept the debugging trade-off

The cost model has three meaningful terms: live forwarded media, retained operational events, and engineering effort spent making recovery deterministic. In an active room, media egress usually deserves the first measurement because it scales with encoded rate, recipient count, and duration. Authorization records are tiny by comparison, but their retention period can multiply compliance scope across many appointments.

Use this planning equation before debating infrastructure:

def forwarded_megabits(avg_mbps: float, recipients: int, seconds: int) -> float:
    return avg_mbps * recipients * seconds


example = forwarded_megabits(avg_mbps=2.5, recipients=7, seconds=900)
assert example == 15750.0
Enter fullscreen mode Exit fullscreen mode

The result is 15,750 megabits of forwarded payload under the stated assumptions, before overhead or retransmission. The useful optimization is therefore to stop a publication promptly when ownership ends, avoid forwarding to disconnected viewers, and measure encoded rate rather than assuming the capture resolution predicts it. Shortening an audit row will not move that live-media term.

Retention still matters for a different reason. Keep authorization decisions for the period required by the organization's clinical, security, and legal policy; no generic article can supply that period. Apply access controls and deletion consistently to backups and derived analytics as well as the primary event store.

Deliberately stop keeping raw signaling bodies once the compact event has been validated, and never retain screen media merely to debug authorization. The cost is real: an intermittent negotiation failure becomes harder to reconstruct packet by packet. Pay that cost consciously. Compensate with correlation identifiers, revision numbers, aggregate error categories, client media statistics, and short-lived restricted diagnostics activated only under an approved incident process.

The decision rule is straightforward: one room owner, one bounded grant tied to authenticated identity, atomic consumption at publication, revisioned current state for recovery, and minimal audit events. That gives the seven recipients a repairable live view without turning a screen-share permission into a permanent publisher credential or a collection of sensitive payloads.

Further reading