Skip to content

feat(oidc): HostSessions::is_same_origin for a host's own writes - #190

Merged
aroff merged 1 commit into
mainfrom
feat/oidc-host-session-same-origin
Oct 17, 2026
Merged

aroff merged 1 commit into
mainfrom
feat/oidc-host-session-same-origin

Conversation

@aroff

@aroff aroff commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Summary

Adds HostSessions::is_same_origin(&HeaderMap) -> bool: true only when the request holds exactly one Origin header, equal byte for byte to the host's own origin (HostSessions::origin()).

A host that admits the session cookie on its own state-changing routes (an API the page calls with the cookie) has to tell its pages from everyone else's. The cookie is SameSite=Lax, so the browser also sends it with requests from other hosts of the same site: two hosts under one registrable domain, for example two hosts under one tailnet's ts.net name (ts.net is a public suffix, so a.<tailnet>.ts.net and b.<tailnet>.ts.net are one site). Sec-Fetch-Site: same-site does not tell those apart. Only Origin does.

Until now, a host had to copy the check. The logout route's cross_site is pub(crate), and it is laxer on purpose: it accepts a POST with no Origin when Sec-Fetch-Site is not cross-site. This PR leaves that route unchanged.

The first user is Pauta (rudaia-hq/pauta), whose page writes through /api/v1 with the session cookie. It keeps a small local copy of this check until this lands.

What could be bypassed, and which test shows it is not

Bypass Refused because Test
A sibling host of the same site posts with the user's Lax cookie its Origin differs is_same_origin_needs_exactly_one_origin_equal_to_the_hosts: "another host of the same site"
A request with no Origin, only Sec-Fetch-Site: same-origin or same-site a missing Origin is false same test, "… alone" cases
A look-alike host, another port or scheme, a trailing slash, null byte equality with the serialized origin same test
Two Origin headers, one of them right exactly one is required same test, "two equal origins", "the host's and another"

Nothing is logged by the new method. No secret is involved.

Checks

  • cargo fmt --all -- --check
  • cargo clippy --all-features -- -D warnings
  • cargo test -p cli-framework-oidc --features host-session,test-support: 169 passed
  • README: a "Your own writes" bullet in the Host session section

🤖 Generated with Claude Code

A host that admits its session cookie on its own state-changing routes
needs to tell its pages from everyone else's. The cookie is SameSite=Lax,
so the browser also sends it with requests from other hosts of the same
site (two hosts under one registrable domain, e.g. under one tailnet's
ts.net name), and Sec-Fetch-Site: same-site does not tell them apart.
Only Origin does.

is_same_origin is true only when the request holds exactly one Origin,
equal byte for byte to the host's origin. A missing Origin is refused:
a browser sends it on every fetch other than GET or HEAD and on every
form POST. The logout route's own check is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aroff
aroff enabled auto-merge (squash) October 17, 2026 20:36
@aroff
aroff merged commit 3b55074 into main Oct 17, 2026
6 checks passed
@aroff
aroff deleted the feat/oidc-host-session-same-origin branch October 17, 2026 21:02
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.

2 participants