Skip to content

Hybrid installs sign in with GitHub through CoderHelm's GitHub App - #459

Merged
nambok merged 1 commit into
mainfrom
hybrid-github-sign-in
Nov 4, 2026
Merged

nambok merged 1 commit into
mainfrom
hybrid-github-sign-in

Conversation

@nambok

@nambok nambok commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Hybrid installs offer Continue with GitHub again, through CoderHelm's GitHub App. The hosted side only carries the trip to GitHub and exchanges a code the install hands it; the install checks the GitHub account with GitHub itself and applies its own sign-in rules. The hosted side can't make a session on an install or choose who signs in. This replaces the "GitHub sign-in off on hybrid" choice from #456.

The flow:

  1. GET /auth/github on the install (no OAuth client of its own, registered with CoderHelm): a new state and PKCE verifier, sealed in a __Host- cookie with the install's own key; a signed POST /hybrid/github/sign-in/start with the install's callback (/auth/github/hybrid-callback), state and S256 challenge. The install checks the answered URL is GitHub's authorize page for that flow and challenge.
  2. GitHub returns to the already registered https://api.coderhelm.com/auth/github/callback/hybrid with state=hsi_…. The hosted side takes the flow once, checks the install is still verified and the address still its own, keeps the code's hash (5 minutes) and forwards the browser with code, state and flow.
  3. The install opens its cookie, matches state and flow, then a signed POST /hybrid/github/sign-in/exchange with the verifier. The hosted side checks the flow is this install's, the code hash and PKCE; GitHub checks the verifier too. The token is answered, not stored or logged.
  4. The install reads the account from GitHub (github_sign_in_with_token, the same function its own client uses: members, invites, allowed domains, no sign-up, two-factor; no installation linking), then POST /hybrid/github/sign-in/revoke has the token revoked at GitHub.

No GitHub App setting changes: the hosted callback is the one hybrid linking already uses.

Changes

  • common/src/hybrid/github_sign_in.rs (new): paths, flow and state shapes, PKCE, redirect check (exact path, install hosts only), authorize URL and its install-side check, sealed cookie, return matching.
  • routes/hybrid.rs: sign_in_start, sign_in_return (dispatched from the existing hosted callback by hsi_ state), sign_in_exchange, sign_in_revoke; audit github_sign_in and github_sign_in_refused.
  • routes/github_hybrid.rs (new): install start and callback.
  • routes/auth.rs: the GitHub callback split at the token; /auth/methods and /auth/github route through CoderHelm when the install has no client and is registered.
  • setup_checks.rs: github_sign_in passes on a registered hybrid install, warns until it is registered.
  • integrations.rs: the Sign in with GitHub card, new mode included, copy says what passes through CoderHelm (no Google mention).
  • Docs: hybrid.md (flow, what CoderHelm sees and can do, operators), sign-in.md, check-your-install.md.

Verification

  • cargo fmt --check --all, cargo clippy -p gateway -p common -p worker --tests -- -D warnings, cargo test -p common -p gateway: 2084 passed.
  • New tests: install side (cookie forged, expired, other install's key, missing; state or flow of another flow; cancelled; only the token read from the hosted answer; refusals that mean setup), hosted side (unsigned, wrongly signed and other-route-signed start, exchange and revoke refused; unknown or malformed flow on the callback answers 400 with no redirect), redirect rules (other hosts, ports, prefixes, queries, paths), authorize URL check, PKCE. Source checks: both GitHub paths reach github_sign_in_with_token, the hybrid callback checks its cookie before calling CoderHelm and makes no session itself; existing rules and two-factor order tests now cover the shared function.

A hybrid install has no GitHub OAuth client of its own, so #456 hid
Continue with GitHub there. People need it to get in, so it now goes
through CoderHelm's app, with the install making every decision.

- The install makes a state and a PKCE verifier, seals them in a
  __Host- cookie with its own key, and asks the hosted side (signed v2)
  to start a flow for its own callback, /auth/github/hybrid-callback.
  The hosted side accepts only that path on the install's verified
  CloudFront or CoderHelm address.
- GitHub returns to the already registered hosted callback
  (/auth/github/callback/hybrid, state=hsi_...). The hosted side takes
  the flow once, checks the install again and forwards the browser with
  the code; it keeps only the code's hash, for 5 minutes.
- The install checks state and flow against its cookie, then asks the
  hosted side (signed) to exchange the code with the verifier; the
  hosted side checks the install, the code hash and PKCE, and GitHub
  checks the verifier too. The token is answered, never stored or
  logged.
- The install reads the GitHub account from GitHub itself and runs the
  same sign-in as its own client would (github_sign_in_with_token:
  members, invites, allowed domains, no sign-up, two-factor), links no
  installations, then has the hosted side revoke the token at GitHub.
- /auth/methods says github: true for a registered hybrid install; the
  github_sign_in check passes there and warns until it is registered.
- The Settings card for Sign in with GitHub says what passes through
  CoderHelm and what stays with the install (new mode: included).
- Docs: hybrid.md has the flow and what CoderHelm sees and can do;
  sign-in.md and check-your-install.md follow.
@nambok
nambok merged commit 69e1195 into main Nov 4, 2026
10 checks passed
@nambok
nambok deleted the hybrid-github-sign-in branch November 4, 2026 16:29
nambok added a commit that referenced this pull request Nov 4, 2026
…461)

Pins dashboardRef to CoderHelm/coderhelm dcc848d (#309): the Sign in
with GitHub card shows the included mode from #459, and the e2e covers
the button on a registered hybrid install.
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