From 63279280fd048657f1e06d32399e5346a65bafe0 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Thu, 1 May 2025 20:41:30 -0300
Subject: [PATCH 1/4] Add Github SSO users to default organization on signup
---
backend/src/server/lib/schemas.ts | 20 ++++++++++
backend/src/server/routes/index.ts | 1 +
backend/src/server/routes/v1/sso-router.ts | 7 +++-
backend/src/server/routes/v3/signup-router.ts | 39 ++++++++++---------
.../src/services/auth/auth-login-service.ts | 31 ++++++++++++++-
.../src/services/auth/auth-signup-service.ts | 28 ++++++++-----
backend/src/services/auth/auth-signup-type.ts | 3 +-
frontend/src/hooks/api/auth/types.ts | 1 +
.../pages/admin/OverviewPage/OverviewPage.tsx | 2 +-
.../auth/SignUpSsoPage/SignUpSsoPage.tsx | 2 +
.../UserInfoSSOStep/UserInfoSSOStep.tsx | 13 ++++---
.../src/pages/auth/SignUpSsoPage/route.tsx | 3 +-
12 files changed, 112 insertions(+), 38 deletions(-)
diff --git a/backend/src/server/lib/schemas.ts b/backend/src/server/lib/schemas.ts
index 9f93eaea0..72ee8eb4f 100644
--- a/backend/src/server/lib/schemas.ts
+++ b/backend/src/server/lib/schemas.ts
@@ -48,3 +48,23 @@ export const SecretNameSchema = BaseSecretNameSchema.refine(
)
.refine((el) => !el.includes(":"), "Secret name cannot contain colon.")
.refine((el) => !el.includes("/"), "Secret name cannot contain forward slash.");
+
+const DefaultOrgSchema = z.object({
+ useDefaultOrg: z.literal(true),
+ organizationName: z.string().trim().optional()
+});
+
+const CustomOrgSchema = z.object({
+ useDefaultOrg: z.literal(false),
+ organizationName: GenericResourceNameSchema
+});
+
+export const OrganizationInputSchema = z.preprocess(
+ (data) => {
+ if (typeof data === "object" && data && "useDefaultOrg" in data === false) {
+ return { ...data, useDefaultOrg: false };
+ }
+ return data;
+ },
+ z.discriminatedUnion("useDefaultOrg", [DefaultOrgSchema, CustomOrgSchema])
+);
diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts
index a71a69c20..cfd6ca84a 100644
--- a/backend/src/server/routes/index.ts
+++ b/backend/src/server/routes/index.ts
@@ -623,6 +623,7 @@ export const registerRoutes = async (
tokenService,
orgDAL,
totpService,
+ orgMembershipDAL,
auditLogService
});
const passwordService = authPaswordServiceFactory({
diff --git a/backend/src/server/routes/v1/sso-router.ts b/backend/src/server/routes/v1/sso-router.ts
index f7a1b973a..5f66a67ca 100644
--- a/backend/src/server/routes/v1/sso-router.ts
+++ b/backend/src/server/routes/v1/sso-router.ts
@@ -23,6 +23,7 @@ import { fetchGithubEmails, fetchGithubUser } from "@app/lib/requests/github";
import { authRateLimit } from "@app/server/config/rateLimiter";
import { AuthMethod } from "@app/services/auth/auth-type";
import { OrgAuthMethod } from "@app/services/org/org-types";
+import { getServerCfg } from "@app/services/super-admin/super-admin-service";
export const registerSsoRouter = async (server: FastifyZodProvider) => {
const appCfg = getConfig();
@@ -342,8 +343,12 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
}`
);
}
+
+ const serverCfg = await getServerCfg();
return res.redirect(
- `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
+ `${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
+ serverCfg.defaultAuthOrgId ? `&defaultOrgAllowed=true` : ""
+ }`
);
}
});
diff --git a/backend/src/server/routes/v3/signup-router.ts b/backend/src/server/routes/v3/signup-router.ts
index d9196dc88..8c786355d 100644
--- a/backend/src/server/routes/v3/signup-router.ts
+++ b/backend/src/server/routes/v3/signup-router.ts
@@ -4,7 +4,7 @@ import { UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { ForbiddenRequestError } from "@app/lib/errors";
import { authRateLimit } from "@app/server/config/rateLimiter";
-import { GenericResourceNameSchema } from "@app/server/lib/schemas";
+import { OrganizationInputSchema } from "@app/server/lib/schemas";
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
@@ -88,24 +88,25 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
rateLimit: authRateLimit
},
schema: {
- body: z.object({
- email: z.string().trim(),
- firstName: z.string().trim(),
- lastName: z.string().trim().optional(),
- protectedKey: z.string().trim(),
- protectedKeyIV: z.string().trim(),
- protectedKeyTag: z.string().trim(),
- publicKey: z.string().trim(),
- encryptedPrivateKey: z.string().trim(),
- encryptedPrivateKeyIV: z.string().trim(),
- encryptedPrivateKeyTag: z.string().trim(),
- salt: z.string().trim(),
- verifier: z.string().trim(),
- organizationName: GenericResourceNameSchema,
- providerAuthToken: z.string().trim().optional().nullish(),
- attributionSource: z.string().trim().optional(),
- password: z.string()
- }),
+ body: z
+ .object({
+ email: z.string().trim(),
+ firstName: z.string().trim(),
+ lastName: z.string().trim().optional(),
+ protectedKey: z.string().trim(),
+ protectedKeyIV: z.string().trim(),
+ protectedKeyTag: z.string().trim(),
+ publicKey: z.string().trim(),
+ encryptedPrivateKey: z.string().trim(),
+ encryptedPrivateKeyIV: z.string().trim(),
+ encryptedPrivateKeyTag: z.string().trim(),
+ salt: z.string().trim(),
+ verifier: z.string().trim(),
+ providerAuthToken: z.string().trim().optional().nullish(),
+ attributionSource: z.string().trim().optional(),
+ password: z.string()
+ })
+ .and(OrganizationInputSchema),
response: {
200: z.object({
message: z.string(),
diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts
index d1b0a550d..6e45ba7e1 100644
--- a/backend/src/services/auth/auth-login-service.ts
+++ b/backend/src/services/auth/auth-login-service.ts
@@ -2,7 +2,7 @@ import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { Knex } from "knex";
-import { OrgMembershipRole, TUsers, UserDeviceSchema } from "@app/db/schemas";
+import { OrgMembershipRole, OrgMembershipStatus, TableName, TUsers, UserDeviceSchema } from "@app/db/schemas";
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { isAuthMethodSaml } from "@app/ee/services/permission/permission-fns";
@@ -20,6 +20,8 @@ import { getServerCfg } from "@app/services/super-admin/super-admin-service";
import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service";
import { TokenType } from "../auth-token/auth-token-types";
import { TOrgDALFactory } from "../org/org-dal";
+import { getDefaultOrgMembershipRole } from "../org/org-role-fns";
+import { TOrgMembershipDALFactory } from "../org-membership/org-membership-dal";
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
import { LoginMethod } from "../super-admin/super-admin-types";
import { TTotpServiceFactory } from "../totp/totp-service";
@@ -48,6 +50,7 @@ type TAuthLoginServiceFactoryDep = {
smtpService: TSmtpService;
totpService: Pick;
auditLogService: Pick;
+ orgMembershipDAL: TOrgMembershipDALFactory;
};
export type TAuthLoginFactory = ReturnType;
@@ -56,6 +59,7 @@ export const authLoginServiceFactory = ({
tokenService,
smtpService,
orgDAL,
+ orgMembershipDAL,
totpService,
auditLogService
}: TAuthLoginServiceFactoryDep) => {
@@ -719,6 +723,31 @@ export const authLoginServiceFactory = ({
authMethods: [authMethod],
isGhost: false
});
+
+ if (authMethod === AuthMethod.GITHUB && serverCfg.defaultAuthOrgId) {
+ let orgId = "";
+ const defaultOrg = await orgDAL.findOrgById(serverCfg.defaultAuthOrgId);
+ if (!defaultOrg) throw new BadRequestError({ message: "Failed to find default organization" });
+ orgId = defaultOrg.id;
+ const [orgMembership] = await orgDAL.findMembership({
+ [`${TableName.OrgMembership}.userId` as "userId"]: user.id,
+ [`${TableName.OrgMembership}.orgId` as "id"]: orgId
+ });
+
+ if (!orgMembership) {
+ const { role, roleId } = await getDefaultOrgMembershipRole(defaultOrg.defaultMembershipRole);
+
+ await orgMembershipDAL.create({
+ userId: user.id,
+ inviteEmail: email,
+ orgId,
+ role,
+ roleId,
+ status: OrgMembershipStatus.Accepted,
+ isActive: true
+ });
+ }
+ }
} else {
const isLinkingRequired = !user?.authMethods?.includes(authMethod);
if (isLinkingRequired) {
diff --git a/backend/src/services/auth/auth-signup-service.ts b/backend/src/services/auth/auth-signup-service.ts
index 58ba9186e..f3205bc3a 100644
--- a/backend/src/services/auth/auth-signup-service.ts
+++ b/backend/src/services/auth/auth-signup-service.ts
@@ -9,7 +9,7 @@ import { isAuthMethodSaml } from "@app/ee/services/permission/permission-fns";
import { getConfig } from "@app/lib/config/env";
import { infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption";
import { generateUserSrpKeys, getUserPrivateKey } from "@app/lib/crypto/srp";
-import { ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
+import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { getMinExpiresIn } from "@app/lib/fn";
import { isDisposableEmail } from "@app/lib/validator";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
@@ -150,7 +150,8 @@ export const authSignupServiceFactory = ({
encryptedPrivateKeyTag,
ip,
userAgent,
- authorization
+ authorization,
+ useDefaultOrg
}: TCompleteAccountSignupDTO) => {
const appCfg = getConfig();
const serverCfg = await getServerCfg();
@@ -293,15 +294,24 @@ export const authSignupServiceFactory = ({
});
if (!organizationId) {
- const newOrganization = await orgService.createOrganization({
- userId: user.id,
- userEmail: user.email ?? user.username,
- orgName: organizationName
- });
+ let orgId = "";
+ if (useDefaultOrg && serverCfg.defaultAuthOrgId) {
+ const defaultOrg = await orgDAL.findOrgById(serverCfg.defaultAuthOrgId);
+ if (!defaultOrg) throw new BadRequestError({ message: "Failed to find default organization" });
+ orgId = defaultOrg.id;
+ } else {
+ if (!organizationName) throw new BadRequestError({ message: "Organization name is required" });
+ const newOrganization = await orgService.createOrganization({
+ userId: user.id,
+ userEmail: user.email ?? user.username,
+ orgName: organizationName
+ });
- if (!newOrganization) throw new Error("Failed to create organization");
+ if (!newOrganization) throw new Error("Failed to create organization");
+ orgId = newOrganization.id;
+ }
- organizationId = newOrganization.id;
+ organizationId = orgId;
}
const updatedMembersips = await orgDAL.updateMembership(
diff --git a/backend/src/services/auth/auth-signup-type.ts b/backend/src/services/auth/auth-signup-type.ts
index 3308b9d12..8bbf302c5 100644
--- a/backend/src/services/auth/auth-signup-type.ts
+++ b/backend/src/services/auth/auth-signup-type.ts
@@ -12,12 +12,13 @@ export type TCompleteAccountSignupDTO = {
encryptedPrivateKeyTag: string;
salt: string;
verifier: string;
- organizationName: string;
+ organizationName?: string;
providerAuthToken?: string | null;
attributionSource?: string | undefined;
ip: string;
userAgent: string;
authorization: string;
+ useDefaultOrg?: boolean;
};
export type TCompleteAccountInviteDTO = {
diff --git a/frontend/src/hooks/api/auth/types.ts b/frontend/src/hooks/api/auth/types.ts
index 32610c28d..cbd20b643 100644
--- a/frontend/src/hooks/api/auth/types.ts
+++ b/frontend/src/hooks/api/auth/types.ts
@@ -107,6 +107,7 @@ export type CompleteAccountSignupDTO = CompleteAccountDTO & {
providerAuthToken?: string;
attributionSource?: string;
organizationName: string;
+ useDefaultOrg?: boolean;
};
export type VerifySignupInviteDTO = {
diff --git a/frontend/src/pages/admin/OverviewPage/OverviewPage.tsx b/frontend/src/pages/admin/OverviewPage/OverviewPage.tsx
index a9242c252..af93b3c2a 100644
--- a/frontend/src/pages/admin/OverviewPage/OverviewPage.tsx
+++ b/frontend/src/pages/admin/OverviewPage/OverviewPage.tsx
@@ -235,7 +235,7 @@ export const OverviewPage = () => {
Default organization
- Select the default organization you want to set for SAML/LDAP/OIDC based
+ Select the default organization you want to set for SAML/LDAP/OIDC/Github
logins. When selected, user logins will be automatically scoped to the
selected organization.
diff --git a/frontend/src/pages/auth/SignUpSsoPage/SignUpSsoPage.tsx b/frontend/src/pages/auth/SignUpSsoPage/SignUpSsoPage.tsx
index 40075ae54..6cb4da82b 100644
--- a/frontend/src/pages/auth/SignUpSsoPage/SignUpSsoPage.tsx
+++ b/frontend/src/pages/auth/SignUpSsoPage/SignUpSsoPage.tsx
@@ -13,6 +13,7 @@ export const SignupSsoPage = () => {
const { t } = useTranslation();
const search = useSearch({ from: ROUTE_PATHS.Auth.SignUpSsoPage.id });
const token = search.token as string;
+ const defaultOrgAllowed = search.defaultOrgAllowed as boolean | undefined;
const [step, setStep] = useState(0);
const [password, setPassword] = useState("");
@@ -57,6 +58,7 @@ export const SignupSsoPage = () => {
password={password}
setPassword={setPassword}
providerAuthToken={token}
+ forceDefaultOrg={defaultOrgAllowed}
/>
);
default:
diff --git a/frontend/src/pages/auth/SignUpSsoPage/components/UserInfoSSOStep/UserInfoSSOStep.tsx b/frontend/src/pages/auth/SignUpSsoPage/components/UserInfoSSOStep/UserInfoSSOStep.tsx
index a6ab0623b..2f2ade8e7 100644
--- a/frontend/src/pages/auth/SignUpSsoPage/components/UserInfoSSOStep/UserInfoSSOStep.tsx
+++ b/frontend/src/pages/auth/SignUpSsoPage/components/UserInfoSSOStep/UserInfoSSOStep.tsx
@@ -30,6 +30,7 @@ type Props = {
name: string;
providerOrganizationName: string;
providerAuthToken?: string;
+ forceDefaultOrg?: boolean;
};
/**
@@ -51,7 +52,8 @@ export const UserInfoSSOStep = ({
providerOrganizationName,
password,
setPassword,
- providerAuthToken
+ providerAuthToken,
+ forceDefaultOrg
}: Props) => {
const [nameError, setNameError] = useState(false);
const [organizationName, setOrganizationName] = useState("");
@@ -84,7 +86,7 @@ export const UserInfoSSOStep = ({
} else {
setNameError(false);
}
- if (!organizationName) {
+ if (!organizationName && !forceDefaultOrg) {
setOrganizationNameError(true);
errorCheck = true;
} else {
@@ -160,7 +162,8 @@ export const UserInfoSSOStep = ({
salt: result.salt,
verifier: result.verifier,
organizationName,
- attributionSource
+ attributionSource,
+ useDefaultOrg: forceDefaultOrg
});
// unset signup JWT token and set JWT token
@@ -267,7 +270,7 @@ export const UserInfoSSOStep = ({
)}
- {providerOrganizationName === undefined && (
+ {!forceDefaultOrg && providerOrganizationName === undefined && (
Organization Name
@@ -279,7 +282,7 @@ export const UserInfoSSOStep = ({
isRequired
className="h-12"
maxLength={64}
- disabled
+ isDisabled={forceDefaultOrg}
/>
{organizationNameError && (
diff --git a/frontend/src/pages/auth/SignUpSsoPage/route.tsx b/frontend/src/pages/auth/SignUpSsoPage/route.tsx
index a255efaf6..986735ad0 100644
--- a/frontend/src/pages/auth/SignUpSsoPage/route.tsx
+++ b/frontend/src/pages/auth/SignUpSsoPage/route.tsx
@@ -5,7 +5,8 @@ import { z } from "zod";
import { SignupSsoPage } from "./SignUpSsoPage";
const SignupSSOPageQueryParamsSchema = z.object({
- token: z.string()
+ token: z.string(),
+ defaultOrgAllowed: z.boolean().optional()
});
export const Route = createFileRoute("/_restrict-login-signup/signup/sso")({
From 365b4b975e331e2dddcfffac67b3de94efde347e Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 2 May 2025 08:22:47 -0300
Subject: [PATCH 2/4] Add minor improvements to Github SSO users added to
default organization on signup
---
backend/src/server/lib/schemas.ts | 3 +--
backend/src/services/auth/auth-login-service.ts | 6 +++++-
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/backend/src/server/lib/schemas.ts b/backend/src/server/lib/schemas.ts
index 72ee8eb4f..7edc98db3 100644
--- a/backend/src/server/lib/schemas.ts
+++ b/backend/src/server/lib/schemas.ts
@@ -50,8 +50,7 @@ export const SecretNameSchema = BaseSecretNameSchema.refine(
.refine((el) => !el.includes("/"), "Secret name cannot contain forward slash.");
const DefaultOrgSchema = z.object({
- useDefaultOrg: z.literal(true),
- organizationName: z.string().trim().optional()
+ useDefaultOrg: z.literal(true)
});
const CustomOrgSchema = z.object({
diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts
index 6e45ba7e1..14663ced6 100644
--- a/backend/src/services/auth/auth-login-service.ts
+++ b/backend/src/services/auth/auth-login-service.ts
@@ -727,7 +727,11 @@ export const authLoginServiceFactory = ({
if (authMethod === AuthMethod.GITHUB && serverCfg.defaultAuthOrgId) {
let orgId = "";
const defaultOrg = await orgDAL.findOrgById(serverCfg.defaultAuthOrgId);
- if (!defaultOrg) throw new BadRequestError({ message: "Failed to find default organization" });
+ if (!defaultOrg) {
+ throw new BadRequestError({
+ message: `Failed to find default organization with ID ${serverCfg.defaultAuthOrgId}`
+ });
+ }
orgId = defaultOrg.id;
const [orgMembership] = await orgDAL.findMembership({
[`${TableName.OrgMembership}.userId` as "userId"]: user.id,
From e12f4ad25339d6aae2c6fb8153110fdc7df72c2b Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 2 May 2025 12:58:36 -0300
Subject: [PATCH 3/4] Add cloud check on github add user to default org
---
backend/src/server/routes/v1/sso-router.ts | 2 +-
backend/src/services/auth/auth-login-service.ts | 2 +-
backend/src/services/auth/auth-signup-service.ts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/backend/src/server/routes/v1/sso-router.ts b/backend/src/server/routes/v1/sso-router.ts
index 5f66a67ca..b6b3cb8aa 100644
--- a/backend/src/server/routes/v1/sso-router.ts
+++ b/backend/src/server/routes/v1/sso-router.ts
@@ -347,7 +347,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
const serverCfg = await getServerCfg();
return res.redirect(
`${appCfg.SITE_URL}/signup/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
- serverCfg.defaultAuthOrgId ? `&defaultOrgAllowed=true` : ""
+ serverCfg.defaultAuthOrgId && !appCfg.isCloud ? `&defaultOrgAllowed=true` : ""
}`
);
}
diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts
index 14663ced6..14aa8f038 100644
--- a/backend/src/services/auth/auth-login-service.ts
+++ b/backend/src/services/auth/auth-login-service.ts
@@ -724,7 +724,7 @@ export const authLoginServiceFactory = ({
isGhost: false
});
- if (authMethod === AuthMethod.GITHUB && serverCfg.defaultAuthOrgId) {
+ if (authMethod === AuthMethod.GITHUB && serverCfg.defaultAuthOrgId && !appCfg.isCloud) {
let orgId = "";
const defaultOrg = await orgDAL.findOrgById(serverCfg.defaultAuthOrgId);
if (!defaultOrg) {
diff --git a/backend/src/services/auth/auth-signup-service.ts b/backend/src/services/auth/auth-signup-service.ts
index f3205bc3a..4d8c98205 100644
--- a/backend/src/services/auth/auth-signup-service.ts
+++ b/backend/src/services/auth/auth-signup-service.ts
@@ -295,7 +295,7 @@ export const authSignupServiceFactory = ({
if (!organizationId) {
let orgId = "";
- if (useDefaultOrg && serverCfg.defaultAuthOrgId) {
+ if (useDefaultOrg && serverCfg.defaultAuthOrgId && !appCfg.isCloud) {
const defaultOrg = await orgDAL.findOrgById(serverCfg.defaultAuthOrgId);
if (!defaultOrg) throw new BadRequestError({ message: "Failed to find default organization" });
orgId = defaultOrg.id;
From 46755f724cc57e8b725b0fad8faab9ab40f1330b Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Fri, 2 May 2025 13:06:45 -0300
Subject: [PATCH 4/4] Improve /complete-account/signup body schema
---
backend/src/server/lib/schemas.ts | 19 ------------------
backend/src/server/routes/v3/signup-router.ts | 20 +++++++++++++++++--
2 files changed, 18 insertions(+), 21 deletions(-)
diff --git a/backend/src/server/lib/schemas.ts b/backend/src/server/lib/schemas.ts
index 7edc98db3..9f93eaea0 100644
--- a/backend/src/server/lib/schemas.ts
+++ b/backend/src/server/lib/schemas.ts
@@ -48,22 +48,3 @@ export const SecretNameSchema = BaseSecretNameSchema.refine(
)
.refine((el) => !el.includes(":"), "Secret name cannot contain colon.")
.refine((el) => !el.includes("/"), "Secret name cannot contain forward slash.");
-
-const DefaultOrgSchema = z.object({
- useDefaultOrg: z.literal(true)
-});
-
-const CustomOrgSchema = z.object({
- useDefaultOrg: z.literal(false),
- organizationName: GenericResourceNameSchema
-});
-
-export const OrganizationInputSchema = z.preprocess(
- (data) => {
- if (typeof data === "object" && data && "useDefaultOrg" in data === false) {
- return { ...data, useDefaultOrg: false };
- }
- return data;
- },
- z.discriminatedUnion("useDefaultOrg", [DefaultOrgSchema, CustomOrgSchema])
-);
diff --git a/backend/src/server/routes/v3/signup-router.ts b/backend/src/server/routes/v3/signup-router.ts
index 8c786355d..552253cde 100644
--- a/backend/src/server/routes/v3/signup-router.ts
+++ b/backend/src/server/routes/v3/signup-router.ts
@@ -4,7 +4,7 @@ import { UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { ForbiddenRequestError } from "@app/lib/errors";
import { authRateLimit } from "@app/server/config/rateLimiter";
-import { OrganizationInputSchema } from "@app/server/lib/schemas";
+import { GenericResourceNameSchema } from "@app/server/lib/schemas";
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
@@ -106,7 +106,23 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
attributionSource: z.string().trim().optional(),
password: z.string()
})
- .and(OrganizationInputSchema),
+ .and(
+ z.preprocess(
+ (data) => {
+ if (typeof data === "object" && data && "useDefaultOrg" in data === false) {
+ return { ...data, useDefaultOrg: false };
+ }
+ return data;
+ },
+ z.discriminatedUnion("useDefaultOrg", [
+ z.object({ useDefaultOrg: z.literal(true) }),
+ z.object({
+ useDefaultOrg: z.literal(false),
+ organizationName: GenericResourceNameSchema
+ })
+ ])
+ )
+ ),
response: {
200: z.object({
message: z.string(),