From ccd7b0587ad61b75bc531b8c41d9576bfe3751b5 Mon Sep 17 00:00:00 2001 From: Anand Hegde Date: Mon, 14 Sep 2026 15:50:57 +0530 Subject: [PATCH 1/3] fix(auth): hide sign-up on login and onboarding when registration is closed With ALLOW_REGISTRATION=false the login page still linked to /onboarding and the onboarding page still rendered the GitHub/Google/email sign-up forms, even though the API rejects the sign-up. Expose getIsRegistrationAllowed through a public auth.isRegistrationAllowed query and use it to hide the link and replace the forms with a short message. Valid invite links and a fresh install with no users still get the sign-up forms, matching the server-side check. --- apps/start/src/routes/_login.login.tsx | 25 ++++++++++------ apps/start/src/routes/_public.onboarding.tsx | 30 ++++++++++++++++++++ packages/trpc/src/routers/auth.ts | 5 ++++ 3 files changed, 51 insertions(+), 9 deletions(-) diff --git a/apps/start/src/routes/_login.login.tsx b/apps/start/src/routes/_login.login.tsx index ef36777ed..646129045 100644 --- a/apps/start/src/routes/_login.login.tsx +++ b/apps/start/src/routes/_login.login.tsx @@ -22,10 +22,15 @@ export const Route = createFileRoute('/_login/login')({ correlationId: z.string().optional(), inviteId: z.string().optional(), }), + loader: ({ context }) => + context.queryClient.ensureQueryData( + context.trpc.auth.isRegistrationAllowed.queryOptions({}) + ), }); function LoginPage() { const { error, correlationId, inviteId } = Route.useSearch(); + const isRegistrationAllowed = Route.useLoaderData(); const [lastProvider] = useCookieStore( 'last-auth-provider', null @@ -35,15 +40,17 @@ function LoginPage() {

Sign in

-

- Don't have an account?{' '} - - Create one today - -

+ {isRegistrationAllowed && ( +

+ Don't have an account?{' '} + + Create one today + +

+ )}
{error && ( +
+

+ {inviteId ? 'Invitation not valid' : 'Registration is disabled'} +

+

+ {inviteId + ? 'This invitation no longer exists or has already been used. Ask an administrator for a new one.' + : "New accounts can't be created on this instance. Ask an administrator to invite you."} +

+

+ Already have an account?{' '} + + Sign in + +

+
+
+ ); + } + return (
diff --git a/packages/trpc/src/routers/auth.ts b/packages/trpc/src/routers/auth.ts index 5f7dec314..bd6252b87 100644 --- a/packages/trpc/src/routers/auth.ts +++ b/packages/trpc/src/routers/auth.ts @@ -589,6 +589,11 @@ export const authRouter = createTRPCRouter({ return ctx.session; }), + // Lets the login/onboarding pages hide sign-up when it would be rejected. + isRegistrationAllowed: publicProcedure + .input(z.object({ inviteId: z.string().nullish() })) + .query(({ input }) => getIsRegistrationAllowed(input.inviteId)), + extendSession: publicProcedure.mutation(async ({ ctx }) => { if (!(ctx.session.session && ctx.cookies.session)) { return { extended: false }; From a0f0f6984e7cf85e462b638ae479bb3af468e7bc Mon Sep 17 00:00:00 2001 From: Anand Hegde Date: Mon, 14 Sep 2026 17:54:06 +0530 Subject: [PATCH 2/3] fix(auth): keep sign-up visible for invited users on login Pass the login page's inviteId to isRegistrationAllowed and carry it into the onboarding link, so invited users still see sign-up when ALLOW_REGISTRATION=false. Reword the invalid-invite message to also cover ALLOW_INVITATION=false. --- apps/start/src/routes/_login.login.tsx | 29 +++++++++++++------- apps/start/src/routes/_public.onboarding.tsx | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/apps/start/src/routes/_login.login.tsx b/apps/start/src/routes/_login.login.tsx index 646129045..89c7c7e0b 100644 --- a/apps/start/src/routes/_login.login.tsx +++ b/apps/start/src/routes/_login.login.tsx @@ -9,6 +9,11 @@ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { useCookieStore } from '@/hooks/use-cookie-store'; import { createTitle, PAGE_TITLES } from '@/utils/title'; +const validateSearch = z.object({ + error: z.string().optional(), + correlationId: z.string().optional(), + inviteId: z.string().optional(), +}); export const Route = createFileRoute('/_login/login')({ component: LoginPage, head: () => ({ @@ -17,15 +22,15 @@ export const Route = createFileRoute('/_login/login')({ { name: 'robots', content: 'noindex, follow' }, ], }), - validateSearch: z.object({ - error: z.string().optional(), - correlationId: z.string().optional(), - inviteId: z.string().optional(), - }), - loader: ({ context }) => - context.queryClient.ensureQueryData( - context.trpc.auth.isRegistrationAllowed.queryOptions({}) - ), + validateSearch, + loader: ({ context, location }) => { + const search = validateSearch.safeParse(location.search); + return context.queryClient.ensureQueryData( + context.trpc.auth.isRegistrationAllowed.queryOptions({ + inviteId: search.success ? search.data.inviteId : undefined, + }) + ); + }, }); function LoginPage() { @@ -45,7 +50,11 @@ function LoginPage() { Don't have an account?{' '} Create one today diff --git a/apps/start/src/routes/_public.onboarding.tsx b/apps/start/src/routes/_public.onboarding.tsx index cdd4d687b..c9c113745 100644 --- a/apps/start/src/routes/_public.onboarding.tsx +++ b/apps/start/src/routes/_public.onboarding.tsx @@ -69,7 +69,7 @@ function Component() {

{inviteId - ? 'This invitation no longer exists or has already been used. Ask an administrator for a new one.' + ? 'This invitation no longer exists, has already been used, or invitations are disabled on this instance. Ask an administrator for help.' : "New accounts can't be created on this instance. Ask an administrator to invite you."}

From 3d3a31e1844342d7dc389d5cb3ec1e84231d4a2f Mon Sep 17 00:00:00 2001 From: Anand Hegde Date: Tue, 15 Sep 2026 08:47:42 +0530 Subject: [PATCH 3/3] fix(auth): use a generic heading when an invited sign-up is unavailable --- apps/start/src/routes/_public.onboarding.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/start/src/routes/_public.onboarding.tsx b/apps/start/src/routes/_public.onboarding.tsx index c9c113745..c8617e4ae 100644 --- a/apps/start/src/routes/_public.onboarding.tsx +++ b/apps/start/src/routes/_public.onboarding.tsx @@ -65,7 +65,9 @@ function Component() {

- {inviteId ? 'Invitation not valid' : 'Registration is disabled'} + {inviteId + ? 'Registration is unavailable' + : 'Registration is disabled'}

{inviteId