Skip to content

feat: hand the hot token over without requiring it - #2486

Merged
alexander-akait merged 2 commits into
mainfrom
feat/hot-token-optional
Oct 18, 2026
Merged

alexander-akait merged 2 commits into
mainfrom
feat/hot-token-optional

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

hot.token also takes { value, required }.

With required: false, the token is minted (or value is used) and handed to the injected client exactly as token: true does. The endpoint, however, lets a client without it through. That is for a server with policy of its own: it reads instance.token and compares it in onConnect, next to whatever else it knows, and closes a client that has neither.

webpack-dev-server needs this (webpack/webpack-dev-server#5770). It already allows the page's own origin, and it can now also accept the token, so HMR works behind a proxy or under a hostname the origin check does not know, with no list of origins. Requiring the token outright would refuse clients the middleware did not inject, which is why the default stays false.

  • HotInstance.tokenRequired says which mode applies; token is still the value the client is given.
  • {} and { value: true } behave like true; { value: false } like false.
  • The "no client entry was added" warning is not printed for a token that is not required, since nothing is refused for want of it.
  • Schema, types, README (hot.token, with an onConnect example) and a minor changeset.

Tests: test/hot.test.js (WebSocket and Server-Sent Events: handed over, not required, onConnect sees the carried token, object defaults) and test/inject-client.test.js (no warning when not required). Unit suite: 7385 passed; the 2 failures are the root-only writeToDisk EACCES cases that fail on main too.


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added an object form for configuring the hot token, with options to provide a token value and allow connections without presenting it.
    • Exposed whether the endpoint requires a token, so connection handlers can apply their own checks. When token enforcement is disabled, the injected client still receives the configured or generated token.
  • Documentation
    • Updated configuration guidance and examples to explain optional token enforcement and checking tokens alongside allowed origins.

`hot.token` also takes `{ value, required }`. With `required: false` the
token is minted (or `value` used) and given to the injected client, but the
endpoint lets a client without it through, so a server with policy of its
own can compare it in `onConnect`. `hot.tokenRequired` says which applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA
@changeset-bot

changeset-bot Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bff00a8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
webpack-dev-middleware Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 1b87643a-c380-475a-af85-7c20777446cb
📥 Commits

Reviewing files that changed from the base of the PR and between b879192 and bff00a8.

📒 Files selected for processing: 3
  • README.md
  • src/options.check.js
  • src/options.json
🚧 Files skipped from review as they are similar to previous changes: 2
  • src/options.json
  • README.md

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Walkthrough

The hot.token option now accepts an object with value and required fields. The hot instance exposes tokenRequired, and transports receive a token only when endpoint enforcement is enabled. Hot-client injection uses tokenRequired when deciding whether to warn about a missing client entry. The schema, TypeScript declarations, README, changeset, and tests document or cover these changes.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to bff00

The documented token options and executable validation agree; no identified issue blocks merging after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: passing the hot token to the client without requiring it.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 8 files. (2 skipped: 2 …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 8 files. (2 skipped: 2 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • 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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 93d10270-b439-4198-b7e8-7c0ac217a556
📥 Commits

Reviewing files that changed from the base of the PR and between d1ecd3d and b879192.

📒 Files selected for processing: 12
  • .changeset/hot-token-not-required.md
  • README.md
  • src/hot.js
  • src/index.js
  • src/options.check.js
  • src/options.json
  • src/utils.js
  • test/hot.test.js
  • test/inject-client.test.js
  • types/hot.d.ts
  • types/index.d.ts
  • types/utils.d.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread README.md Outdated
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.59%. Comparing base (d1ecd3d) to head (bff00a8).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2486      +/-   ##
==========================================
+ Coverage   96.55%   96.59%   +0.04%     
==========================================
  Files          24       24              
  Lines        2640     2644       +4     
==========================================
+ Hits         2549     2554       +5     
+ Misses         91       90       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait
alexander-akait merged commit 32f3902 into main Oct 18, 2026
24 checks passed
@alexander-akait
alexander-akait deleted the feat/hot-token-optional branch October 18, 2026 16:18
alexander-akait added a commit to webpack/webpack-dev-server that referenced this pull request Oct 18, 2026
…th allowedOrigins

8.5.0 takes `hot.token: { required: false }` (webpack/webpack-dev-middleware#2486),
so the check for it, the tests' stand-in token and the README notes on older
versions go, as their TODOs said. The token is handed to the injected client
only once `allowedOrigins` is set: under "auto" the socket's url and who it
lets in stay exactly as before, with a TODO to always hand it over in the
next major release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA
alexander-akait added a commit to webpack/webpack-dev-server that referenced this pull request Oct 20, 2026
…th allowedOrigins

8.5.0 takes `hot.token: { required: false }` (webpack/webpack-dev-middleware#2486),
so the check for it, the tests' stand-in token and the README notes on older
versions go, as their TODOs said. The token is handed to the injected client
only once `allowedOrigins` is set: under "auto" the socket's url and who it
lets in stay exactly as before, with a TODO to always hand it over in the
next major release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA
alexander-akait added a commit to webpack/webpack-dev-server that referenced this pull request Oct 20, 2026
* fix: separate origin authorization from allowed hosts

* test: clarify origin configuration coverage

* fix: support HMR on a separate port

* feat: keep "auto" origins as they were, deny secrets in static, accept the hot token

`allowedOrigins: "auto"` (the default) now keeps the origin rules derived
from `allowedHosts` exactly, so nothing changes until the option is set;
`allowedHosts: "all"` and an `Access-Control-Allow-Origin: *` header still
open every origin under it, with a deprecation warning. A list allows the
page's own hostname plus the listed origins, answers them with CORS
headers and allows a plain script they load by its `Referer`; "all" allows
every origin and keeps the `Host` check. One rule now serves ordinary
requests, proxied WebSocket upgrades, hot clients and the internal
endpoints.

The injected hot client is handed a per-run token the endpoint does not
require (webpack-dev-middleware#2486), and a client carrying it may connect
from an origin the server does not know; skipped with an older middleware.

`static.deny` refuses secrets (`.env*`, keys and certificates, `.npmrc`,
`.yarnrc.yml`, `.git`) or patterns of your own in a static directory, and
hides them from listings; off by default until the next major.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* chore: note what the next major release removes from the origin rules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* fix: keep the CommonJS build's injected require usable in hotOptions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* chore: regenerate types

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* docs: describe a list's hostname rule and the token's middleware requirement

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* feat: answer an allowed origin's preflight and credentialed requests

With allowedOrigins set, a listed origin gets Access-Control-Allow-Credentials,
and an allowed origin's preflight gets the method, headers and Private
Network Access it asks for, so a fetch with custom headers, another method
or cookies works from it. "auto" is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* test: cover the token, static.deny's edge cases and the list without a Host

The hot-token tests now give the middleware a token when it has none, so
this server's own check runs on any webpack-dev-middleware rather than
being skipped; the optional-token detection takes a schema and is tested
on its own. static.deny gets the `?` glob, an undecodable path and the
Windows rules. The allowedOrigins entry check the schema already makes is
gone, and the token is read off the query without a try that cannot fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* fix: give credentials to listed origins only

A list also allows the page's own hostname on any port, and cookies do not
tell ports apart, so Access-Control-Allow-Credentials went to any other
local page with it. It now goes only to an origin listed by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* chore: say in the TODOs to bump webpack-dev-middleware for the optional token

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

* feat: require webpack-dev-middleware 8.5.0 and hand the token over with allowedOrigins

8.5.0 takes `hot.token: { required: false }` (webpack/webpack-dev-middleware#2486),
so the check for it, the tests' stand-in token and the README notes on older
versions go, as their TODOs said. The token is handed to the injected client
only once `allowedOrigins` is set: under "auto" the socket's url and who it
lets in stay exactly as before, with a TODO to always hand it over in the
next major release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjuMAuk9o6UazjHzcAQCTA

---------

Co-authored-by: alexander-akait <4567934+alexander-akait@users.noreply.github.com>
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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant