Repository navigation
Add POST /invite-codes/disable, authenticated by Cloudflare Access - #17
Merged
Merged
Conversation
The vetting tool needs to disable an invite code when it blocks the applicant that code was issued to. A code already sitting in someone's inbox outlives the decision to bar them, so blocking without revoking leaves a working way in (NorthskySocial/invite-vetting#38). /disable-invite-codes already does this, but authenticates with the browser session cookie and an OTP check. A service holding a Cloudflare Access token cannot satisfy that extractor, so the endpoint is unreachable from another Worker. This mirrors /invite-codes/issue, which exists as the machine-facing counterpart to /create-invite-codes for exactly the same reason. The browser-facing route is left alone. Disabling is unconditional and idempotent. A redeemed code cannot be redeemed again, so disabling it is a no-op rather than something to check for first — and checking would mean trusting a use-count read taken a moment before the write. An empty request is rejected rather than reported as success: disabling nothing and returning 200 reads to the caller exactly like a code having been revoked, which is the one outcome that must not be indistinguishable from failure here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
northernpolaris
approved these changes
Sep 9, 2026
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.
Prerequisite for NorthskySocial/invite-vetting#38 — "blocking a user should invalidate their invite code if they have an unused one".
Why a new route
/disable-invite-codesalready disables codes, but it authenticates withInviteCodeAdmin, which extracts fromtower_sessions::Sessionplus an OTP check — a browser cookie. The vetting Worker holds a Cloudflare Access service token, which satisfiesAccessClientonly, so that endpoint is unreachable from it.That is the same asymmetry
/invite-codes/issuewas added to solve:/create-invite-codes/invite-codes/issue/disable-invite-codes/invite-codes/disable(this PR)The browser-facing route is untouched, so the admin UI is unaffected.
Behaviour
Same request body as the existing route (
DisableInviteCodeSchema—codesandaccounts), same call through tocom.atproto.admin.disableInviteCodes.Disabling is unconditional and idempotent. The issue says "if they have an unused one", but a redeemed code cannot be redeemed again, so disabling it is a no-op — and checking first would mean trusting a use-count read taken a moment before the write. Unconditional is both simpler and free of that race.
An empty request is a 400, not a 200. Disabling nothing and reporting success reads to the caller exactly like a code having been revoked, and that is the one outcome here that must not be indistinguishable from failure.
Checks
cargo buildcleancargo test— 57 passing, 5 newcargo clippy --all-targetsclean,cargo fmt --checkcleanThe new tests mirror
issue_invite_code's: no assertion, forged assertion, and Access unconfigured all give 401, and the PDS is never reached before authenticating (pds_endpointpoints at a closed port, so a 401 also proves no outbound call was attempted).Deploy ordering
This must ship before the vetting-tool side, which I am writing next. Nothing depends on it until then, so it is safe to merge on its own.
🤖 Generated with Claude Code