Repository navigation
Limit OAuth to 37signals staff while it's piloted - #3249
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
🤖 @codex review |
There was a problem hiding this comment.
🔵 Needs a closer look
Security-sensitive OAuth admission and replay-revocation changes need human validation because runtime behavior was not verified during review.
No open issues 🎉
What changed in this PR
Adds a staff-only OAuth pilot gate before the consent-screen rollout. The gate restricts people independently of existing client controls while preserving personal access tokens and grant management.
Changes:
- Enforces staff admission for consent, code redemption, refresh, OAuth token use, delegation, and app push delivery.
- Preserves replay-triggered revocation and adds coverage for loss of staff status and personal-token exemptions.
- Enables the gate in production, staging, and beta deployments.
[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or rungh pr ready --undo.
Click "Ready for review" or rungh pr readyto reengage.
| File | Description |
|---|---|
test/test_helpers/oauth_availability_test_helper.rb |
Adds staff-only configuration isolation for tests. |
test/models/oauth/availability_test.rb |
Tests identity admission and strict boolean configuration. |
test/integration/oauth_token_exchange_test.rb |
Tests delegation refusal after staff status is removed. |
test/integration/oauth_staff_only_test.rb |
Covers consent, redemption, refresh, replay revocation, and personal-token exemptions. |
test/integration/oauth_delegate_resources_test.rb |
Tests push-delivery gating and avoids identity loading when disabled. |
saas/config/deploy.staging.yml |
Enables staff-only OAuth in staging. |
saas/config/deploy.production.yml |
Enables staff-only OAuth in production. |
saas/config/deploy.beta.yml |
Enables staff-only OAuth in beta. |
config/environments/production.rb |
Parses the staff-only environment switch. |
app/views/oauth/authorizations/staff_only.html.erb |
Adds the staff-only consent refusal page. |
app/models/push/subscription.rb |
Stops app push delivery for nonstaff while gated. |
app/models/oauth/availability.rb |
Defines and documents staff admission checks. |
app/models/identity/access_token.rb |
Gates OAuth token use and extracts code-replay handling. |
app/controllers/oauth/tokens_controller.rb |
Gates issuance while preserving replay-triggered revocation. |
app/controllers/oauth/authorizations_controller.rb |
Refuses nonstaff consent requests while allowing denial. |
Review effort: Balanced
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14fbb6d7ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
🤖 @codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
… lock clause from logged SQL
|
🤖 @codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |

Supersedes #3246 for ordering: the staff gate now lands before the consent design (#3212), so main never carries #3212 without the gate. Same change as #3246's final head (c32b732), applied to #3229's head; #3212 now merges this branch and sits on top of it.
Stacked on #3214.
OAUTH_STAFF_ONLY=truelimits OAuth to staff (Identity#staff?), whichever client asks.Oauth::Availability's acceptance, issuance and pilot switches choose clients; this one chooses people, and composes with them: a request has to pass both.This works like Basecamp's, where only staff can authorize an agent for now, and anyone else is told so, not shown a 404.
What's gated
invalid_grant, even for a code issued while they were staffinvalid_grant. The grant stays, for its owner to revoke.invalid_token, viaIdentity::AccessToken#honored?honored?Gating
honored?means someone who stops being staff loses what they connected on their next request. That's the only part that runs per request, and it reads the identity, which is already loaded to authenticate.Turning it on
OAUTH_STAFF_ONLY: "true"is set in the clear env of the production, staging and beta deploy configs, so OAuth lands staff-gated everywhere it might be lit. Opening it up means removing those lines. Anything but exactly"true"is off, and OSS installs never set it.Tests
test/integration/oauth_staff_only_test.rbcovers:The exchange test covers a de-staffed subject and its delegated token.
Oauth::AvailabilityTestcoversadmits?and exact-trueparsing.I removed each of the four gates in turn, and each removal fails at least one of these tests.
Stacking note
The personal-access-token exemption reads
oauth_client_id.nil?here, as C does. #3205 moves PATs onto a first-party client and addspersonal?. When the two meet, this check becomespersonal?, or every PAT would be gated.