Skip to content

fix(auth): present a lost AUTH stream's token again on the same session - #6734

Merged
kixelated merged 5 commits into
mainfrom
quest/m1/auth/token-represent
Oct 25, 2026
Merged

kixelated merged 5 commits into
mainfrom
quest/m1/auth/token-represent

Conversation

@kixelated

@kixelated kixelated commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Finishes quest m1/auth/token-represent (its file and its link in the m1/auth epic are deleted here).

Problem

Since moq-dev/moq#6109, when a shared auth handle's token lost its AUTH stream with no verdict, the token was left for the next session. Examples: the peer resets the stream after a grant, or a retry's stream closes before its reply. The current session ran on without it: grant() read None, a request naming it lost its credential, and closed() waited for a reconnect that might never come. The moq-transport presenter had no retry loop at all. This was raised in mriise's review (bug 1) and by a Codex finding on that PR.

Approach

Any end of a token's stream now goes through one decision, Link::retry in Rust and the loop condition in JS AuthSession.#run. On an active session, a still-wanted token is presented again with the existing backoff (1s doubling to 30s, reset by a grant) in two cases:

  • the peer refused it with a code that may pass (unchanged, lite only), or
  • on a shared handle, its stream ended without a verdict.

A verdict is still only a refusal that will not pass, Unsupported, or a clean close after a grant.

  • rs/moq-net auth.rs:
    • verdict() is factored out and shared by retry and ended.
    • retry now requires an active session, so a draining one never presents again.
    • A transient refusal on a draining session is no longer a verdict, so the successor presents the token instead.
  • rs/moq-net lite: PresentToken loops on retry for every stream end, not just AUTH_ERROR. Retry carries answered, so a lost attempt before any reply still reads as Unsupported.
  • rs/moq-net ietf: run_present gets the same retry loop, with Present::reopen waiting out the backoff (withdrawal still wakes it). answered carries across attempts, as on lite. A stream reset before any reply now reads as Unsupported, matching lite and js/net, instead of being presented again.
  • js/net: mirrors this. A grant now also sets replied, so a reset after a grant is a lost stream, not Unsupported.

Choices made without asking:

  • A session's own handle (Session::auth() without Client::with_auth) still ends a lost token instead of retrying, so the application hears about it, as the quest scoped this to the shared handle.
  • The session's own setup credential is also presented again when its stream is lost on a shared handle, since the session should not run on without it either.

Impact

  • Public API: none. Wire: none.
  • Behavior: on Rust moq-transport, a peer that resets a token's Auth request before any reply now fails the token as Unsupported, as lite and js/net already did. Before this PR the token waited for the next session.
  • Behavior: on a shared handle, a lost AUTH stream (lite) or Auth request (moq-transport) is presented again on the live session after a backoff, instead of waiting for a reconnect. Each moq-transport retry spends one request ID, at most one per token per backoff step.

Tests

  • Rust unit (auth.rs): a lost stream is presented again, its backoff doubles and a grant resets it, a request keeps carrying the token, and a request it might cover waits. A clean close after a grant still settles it. A draining session leaves an undecided token to its successor. A session's own handle ends a lost token.
  • Rust session: lite::session::tests::a_lost_stream_is_presented_again, a_lost_retry_is_presented_again (was a_lost_retry_keeps_a_shared_token), and ietf::session::tests::a_lost_auth_request_is_presented_again. All use mocked time and check presentations at 0s, 1s, and 3s. ietf::session::tests::an_auth_request_reset_before_its_reply_is_unsupported checks that the token is presented once and ends as Unsupported.
  • The scripted test transport gains Close::ResetStream(code), a real reset of one stream. The existing Close::Reset fails the read as a session close, so the lost-stream tests now use the new variant.
  • JS: a shared handle presents a token whose stream is lost again on the same session on lite-07, moqt-17, and moqt-22, plus lite-07 presents a shared token again when its retry stream is reset.
  • Reproduced first: with lost-stream retries disabled, the new Rust session and unit tests fail, and so do the new JS tests against the old auth_session.ts. The reset-before-reply test fails without its mapping, because the token is presented 3 times.
  • just check passes. just test interop --all was not run (no wire change).

🤖 Generated with Claude Code

(Written by Claude Opus 5.5)

kixelated and others added 2 commits October 24, 2026 22:49
When a shared auth handle's token loses its AUTH stream without a verdict,
the session presents it again with the transient-refusal backoff (1s
doubling to 30s, reset by a grant), on moq-lite and moq-transport, in Rust
and JS. Previously the token waited for the next session, and the
moq-transport presenter had no retry loop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title A lost AUTH stream re-presents its token fix(auth): present a lost AUTH stream's token again on the same session Oct 25, 2026
@kixelated
kixelated marked this pull request as ready for review October 25, 2026 07:00
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fc058da6-6335-4220-8bd8-6b083efdf6ce
Commits

Reviewing files that changed from the base of the PR and between 1439302 and 9fb816b.

Files selected for processing: 9
  • js/net/src/auth.test.ts
  • js/net/src/auth_session.ts
  • quest/m1/auth/README.md
  • quest/m1/auth/token-represent.md
  • rs/moq-net/src/auth.rs
  • rs/moq-net/src/ietf/auth.rs
  • rs/moq-net/src/ietf/session.rs
  • rs/moq-net/src/lite/session.rs
  • rs/moq-net/src/lite/test_transport.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T17:48:28.806329Z 9fb816b New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8268dc637

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread js/net/src/auth_session.ts Resolved

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: b8268dc

Centralizing the retry/verdict decision and preserving backoff across unanswered attempts is a sensible, contained fix. The draining-session guard and grant-reset behavior fit the intended lifecycle.

Confirmed existing P2: abort the previous AUTH stream before retrying #6734 (comment). In js/net/src/auth_session.ts:888–928, a read-side reset leaves the writer open before its stream reference is discarded. Abort the abandoned stream before retrying, and cover a peer writer-only reset so retries cannot exhaust stream credit. Referenced instead of duplicated inline.

No additional actionable bugs found in changed Rust/JS retry and token-settlement paths. Static inspection of the patch, surrounding stream/lifecycle code and added tests; tests were not run.

…upported

Matches moq-lite and js/net: a peer that resets a token's Auth request
before replying gave it nothing, so the token fails as unsupported instead
of being presented again. The scripted test transport gains a real
stream reset, so the lost-stream tests reset one stream rather than
failing it as a session close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 12e82af

Compared with b8268dc. The update sensibly aligns Rust moq-transport with lite/JS when an AUTH request resets before its first reply, and corrected stream-reset fixtures make tests more representative.

No new actionable bugs found in this delta. Previously confirmed JS stream-cleanup finding remains open: #6734 (comment). js/net/src/auth_session.ts:888–928 is unchanged, so a read-side reset still abandons the sending half before retrying. This is not a new finding.

Verification: static inspection of the complete incremental diff and surrounding retry/error handling. Tests were not run.

kixelated and others added 2 commits October 25, 2026 10:38
A peer that resets only its sending half left ours open, so each retry
abandoned a stream and its credit until the session ended.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 9fb816b

Compared with 12e82af, accounting for the main merge. The previously confirmed AUTH stream-cleanup finding is fixed: #6734 (comment). js/net/src/auth_session.ts:889–891 now aborts both halves before discarding the stream and retrying. The added writer-only reset test checks the abandoned peer reader is reset before the next successful presentation across lite-07, draft-17 and draft-22.

No new actionable bugs found. This is a small, appropriate lifecycle fix without extra retry machinery.

Verification: static inspection of the incremental fix, surrounding retry/stream cleanup and regression test; tests were not run.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Landing. Merged main and fixed the Codex finding: the JS retry now aborts both halves of an AUTH stream the peer half-reset, with a writer-only-reset regression across lite-07, draft-17, and draft-22. Codex (thumbs-up) and OpenAI found nothing on 9fb816b; just check and quest check pass.

(Written by Claude Opus 5.5)

@kixelated
kixelated added this pull request to the merge queue Oct 25, 2026
Merged via the queue into main with commit bd3c597 Oct 25, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m1/auth/token-represent branch October 25, 2026 20:10
kixelated added a commit that referenced this pull request Oct 25, 2026
The adapter's lost-AUTH change (#6734) goes with the adapter; its session
tests move to draft 18. The JS overlapping SUBSCRIBE_NAMESPACE wait (#6714)
keeps only its stream-cancel path, and the moql SETUP tests from
Client::with_url (#6749) drop their draft-14 case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant