Repository navigation
Self-host: one organization, closed sign-up, admin-required two-factor sign-in - #314
Merged
Merged
Conversation
nambok
force-pushed
the
feat/selfhost-single-org-2fa
branch
from
October 26, 2026 18:46
506931c to
c885bed
Compare
…s on reset, removal, role change or turning it off
nambok
force-pushed
the
feat/selfhost-single-org-2fa
branch
from
October 26, 2026 20:14
c885bed to
daafb88
Compare
nambok
added a commit
that referenced
this pull request
Nov 4, 2026
Security fix. Since #464 forgot-password on a self-hosted install answered with a different status per case (has an account, on the team without one, invited, not on this install), so anyone could learn which emails have accounts or are on the team. Forgot password now answers the same status, body and headers for every email on every install, and no sooner than 2.5 seconds after the ask, so the case can't be timed either: the work (the Cognito reset code, or the set-up email for a team member with no account here) runs while the answer waits, and a slow send carries on after it. Send failures are logged, never answered. The set-up email keeps its once-an-hour limit and the 10/h per IP and 5/h per email limits stay. Self-hosted sign-up answers the same way for invited, existing and refused emails, with the password rules checked for every email first; an email that signed up but never confirmed gets a fresh code. The app client now has preventUserExistenceErrors on. Pins the dashboard to d26225b (CoderHelm/coderhelm #314): the sign-in page shows one message for every email and names both senders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A self-hosted install is now one organization, closed to sign-ups, and admins can require two-factor sign-in.
SignUpcall (a new pre-sign-up trigger checks the same rules).signuplist is the first-boot default: its addresses become invites and its domains the allowed domains.Retry-After.sessions_valid_after. The auth middleware reads the record on every session request and refuses a session issued before that time, or one whose record is gone. This applies on hosted too, for removals and role changes.Dashboard and install guide: CoderHelm/coderhelm229
Changes
routes/sign_in.rs(new):decide_join, the one join decision;GET/PUT /api/sign-in,GET /api/users/2fa, the/api/users/2fa/appsetup, verify and disable routes,POST /api/users/:id/2fa/resetandPOST /auth/2fa/verify.auth/jwt.rs: aSignInProof(second factor passed, and the way in) carried in the session token beside the claims, and a five-minute second-step token. Every token re-issue keeps it.middleware/auth.rs: on a self-hosted install, it checks the rule on each session request before the role check.routes/auth.rs:not_invited;selfhost_landing, never a new team;routes/users.rs:permissions.rs: a newsign_incapability (admins, never in a custom role). The setup routes go underown_account.lambda/pre-signup(new, Node): the Cognito trigger. It reads only, fails closed, and is tested againstcases.json, the same cases the Rust test reads.kind(admin, invite, domain);signup.requireTwoFactorsetting.RequireTwoFactorparameter.self-host/sign-in.mdrewritten: one organization, invites, domains, two-factor, reset, and why authenticator apps rather than passkeys;Verification
cargo fmt --check,cargo clippy --workspace --tests -D warnings: clean.cargo test --workspaceafter rebasing on main (Self-host: switch the model provider at any time, and check a release's models before updating #318): 1009, 2, 506 (gateway) and 687 passed. New tests:node --test lambda/pre-signup/handler.test.js: 6 passed. Covers the shared cases, a direct SignUp from a stranger, Google sign-ups, invites and the first admin, and failing closed.npm test: 66 passed. New tests:signup.requireTwoFactoris checked.cfn-linton the templates: clean. Python Lambda tests: OK.