Repository navigation
feat(auth): Replace Slack sign-in with an allowed domain list - #2229
Merged
Merged
Conversation
Remove the experimental slack-sign-in pre-auth flow. One optional, recommended domain list (dashboard.allowedGoogleDomains) now limits both surfaces: - Slack: mentions and DMs start a Turn only when the author's Slack-verified profile email is on an allowed domain. - Google: dashboard sign-in accepts only Workspace accounts whose verified hd claim is on an allowed domain. Junior sends hd=<domain> for one domain and hd=* for more. Drop the email allowlist (allowedEmails, JUNIOR_DASHBOARD_ALLOWED_EMAILS). Co-Authored-By: Sergiy Deceive-skiy <3760543+sergical@users.noreply.github.com> Co-Authored-By: David Cramer <david@sentry.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dcramer
marked this pull request as ready for review
October 26, 2026 18:37
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 950279d. Configure here.
Domain allowlisting gates Slack and the dashboard, so it no longer lives
under dashboard or carries a Google-specific name. Configure it with
createApp({ allowedDomains }) or JUNIOR_ALLOWED_DOMAINS. Startup fails on
the removed dashboard.allowedGoogleDomains and
JUNIOR_DASHBOARD_GOOGLE_DOMAINS so a stale config cannot silently allow
every Slack workspace member.
Co-Authored-By: David Cramer <david@sentry.io>
decodeJwt throws on a malformed compact JWT before the claims schema runs, so a bad id_token still returned a 500 from the callback. Catch it and return null so Better Auth redirects with unable_to_get_user_info.
Drop stale comments that still describe a Google session shared with Slack, read the Slack profile email domain only when the email has an @, and remove a unit test that duplicated the createApp legacy-name coverage. Co-Authored-By: David Cramer <david@sentry.io>
New apps from junior init set allowedDomains to example.com so the recommended domain gate is visible from the start. Docs snippets use the same placeholder. Co-Authored-By: David Cramer <david@sentry.io>
…sign-in-domain-allowlist Co-Authored-By: David Cramer <david@sentry.io>
dcramer
approved these changes
Oct 26, 2026
This branch was successfully deployed
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.

This removes the experimental
slack-sign-instep that required a Google sign-in before using Junior in Slack (#2220). In its place, one optional domain list limits who can use Slack and who can sign in to the dashboard. Setting the list is recommended. Slack and Google each verify the domain.One list:
createApp({ allowedDomains })/JUNIOR_ALLOWED_DOMAINSjunior initscaffoldsallowedDomains: ["example.com"]as a placeholder, and the quickstart docs show the same.chat/ingress/slack-allowed-domain.ts. Results are cached for 5 minutes when allowed and 30 seconds when not, like the membership check.getUserInfoaccepts an account only when the ID token'shdclaim is on the list. It does not use the email domain. A personal Google account can carry any verified email, for example an ex-employee's@sentry.ioaddress. Only Workspace accounts gethd.hdhint: with one domain, Google getshd=<domain>. With more than one, it getshd=*, so the account chooser shows only Workspace accounts. Better Auth's built-inhdcheck supports only one domain, so Junior replaces itsgetUserInfo.app.allowed_domains.unset. Dashboard auth still requires at least one domain.Removed
slack-sign-inexperiment,slack.signInMaxAgeDays,/api/sign-in/slack, and the Slack sign-in state and prompt. AlsoslackUserHasGoogleSignInandfindSlackIdentityUserId, which nothing else used.dashboard.allowedEmailsandJUNIOR_DASHBOARD_ALLOWED_EMAILS. It cannot be checked againsthd./api/configno longer returnsallowedEmailCount.dashboard.allowedGoogleDomainsandJUNIOR_DASHBOARD_GOOGLE_DOMAINS, replaced by the top-level setting./api/configreturnsallowedDomainCountinstead ofallowedGoogleDomainCount./api/auth/*when the dashboard is not mounted. Only the Slack gate needed that.Rollout
experimental["slack-sign-in"]before it upgrades, because the removed flag now throws at startup. That landed in getsentry/junior-prod#544.dashboard.allowedGoogleDomainsorJUNIOR_DASHBOARD_GOOGLE_DOMAINSis set, so a stale config cannot leave the list empty and let every Slack workspace member in. junior-prod must movedashboard.allowedGoogleDomains: ["sentry.io"]to top-levelallowedDomains: ["sentry.io"]before it upgrades.["sentry.io"], so Slack users with emails on other domains are blocked.Adversarial review
Fixed in this PR:
users:read.emailwould block everyone with no signal. Rejections now logslack.allowed_domain.rejected, withapp.reasonset tomissing_emailordomain_not_allowed.Open issues, worth a decision:
hdon the session so each read could recheck it. Better Auth only copies provider profile fields forinput: trueadditional fields, and those are writable through/update-user. So I backed that out. Effect: sign-in is gated onhd, and existing sessions and personal tokens are rechecked against the email domain. A Workspace user whose email is on an alias domain (hd=sentry.io, email@sentry.dev) gets a 403.users.infocalls, one for membership and one for the domain check. Both are cached. They could be merged later.recordGoogleSignInstill writessigned_in_at, and nothing reads it now. I kept the identity write and did not add a migration to drop the column.Verification
main(TypeScript 7 upgrade). Repo-widepnpm typecheckandpnpm lintpass.oauth-identity-linktimes out at 5s in this sandbox, including on the base commit, so that one isn't verified here.via David Cramer.
--
View Junior Session [Sentry]