Skip to content

Commit d12c871

Browse files
committed
fix(self-host): resolve SSO and access-control in the UI, not the raw env var
Nine client consumers still read NEXT_PUBLIC_SSO_ENABLED / NEXT_PUBLIC_ACCESS_CONTROL_ENABLED directly while the server gates and settings nav had moved to the resolver. With only ENTERPRISE_ENABLED set that produced dead ends: the SSO settings section appeared but ssoClient() was never registered and no login button rendered, and the Access Control section appeared but its page reported "not entitled". Points every consumer at isSsoEnabled / isAccessControlEnabled so visibility and capability come from one place.
1 parent a548903 commit d12c871

9 files changed

Lines changed: 27 additions & 22 deletions

File tree

apps/sim/app/(auth)/components/sso-login-button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22
import { Chip, cn } from '@sim/emcn'
33
import { useRouter } from 'next/navigation'
4-
import { getEnv, isTruthy } from '@/lib/core/config/env'
4+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
55
import { AUTH_BUTTON_CLASS } from '@/app/(auth)/components/constants'
66

77
interface SSOLoginButtonProps {
@@ -17,7 +17,7 @@ export function SSOLoginButton({
1717
}: SSOLoginButtonProps) {
1818
const router = useRouter()
1919

20-
if (!isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED'))) {
20+
if (!isSsoEnabled) {
2121
return null
2222
}
2323

apps/sim/app/(auth)/login/login-form.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { useRouter, useSearchParams } from 'next/navigation'
1616
import { requestJson } from '@/lib/api/client/request'
1717
import { forgetPasswordContract } from '@/lib/api/contracts'
1818
import { client } from '@/lib/auth/auth-client'
19-
import { getEnv, isFalsy, isTruthy } from '@/lib/core/config/env'
19+
import { getEnv, isFalsy } from '@/lib/core/config/env'
20+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
2021
import { validateCallbackUrl } from '@/lib/core/security/input-validation'
2122
import { getBaseUrl } from '@/lib/core/utils/urls'
2223
import { quickValidateEmail } from '@/lib/messaging/email/validation'
@@ -343,7 +344,7 @@ export default function LoginPage({
343344
}
344345
}
345346

346-
const ssoEnabled = isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED'))
347+
const ssoEnabled = isSsoEnabled
347348
const emailEnabled = !isFalsy(getEnv('NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED'))
348349
const hasSocial = githubAvailable || googleAvailable || microsoftAvailable
349350
const hasOnlySSO = ssoEnabled && !emailEnabled && !hasSocial

apps/sim/app/(auth)/signup/signup-form.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import { createLogger } from '@sim/logger'
66
import { useRouter, useSearchParams } from 'next/navigation'
77
import { usePostHog } from 'posthog-js/react'
88
import { client, useSession } from '@/lib/auth/auth-client'
9-
import { getEnv, isFalsy, isTruthy } from '@/lib/core/config/env'
9+
import { getEnv, isFalsy } from '@/lib/core/config/env'
10+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
1011
import { validateCallbackUrl } from '@/lib/core/security/input-validation'
1112
import { quickValidateEmail } from '@/lib/messaging/email/validation'
1213
import { captureClientEvent, captureEvent } from '@/lib/posthog/client'
@@ -360,7 +361,7 @@ function SignupFormContent({
360361
}
361362
}
362363

363-
const ssoEnabled = isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED'))
364+
const ssoEnabled = isSsoEnabled
364365
const emailEnabled =
365366
!isFalsy(getEnv('NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED')) && emailSignupEnabled
366367
const hasSocial = githubAvailable || googleAvailable || microsoftAvailable

apps/sim/app/(auth)/sso/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Suspense } from 'react'
22
import type { Metadata } from 'next'
33
import { redirect } from 'next/navigation'
4-
import { getEnv, isTruthy } from '@/lib/core/config/env'
4+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
55
import SSOForm from '@/ee/sso/components/sso-form'
66

77
export const metadata: Metadata = {
@@ -11,7 +11,7 @@ export const metadata: Metadata = {
1111
export const dynamic = 'force-dynamic'
1212

1313
export default async function SSOPage() {
14-
if (!isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED'))) {
14+
if (!isSsoEnabled) {
1515
redirect('/login')
1616
}
1717

apps/sim/app/(landing)/components/auth-modal/auth-modal.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import { GithubIcon, GoogleIcon, MicrosoftIcon } from '@/components/icons'
1818
import { requestJson } from '@/lib/api/client/request'
1919
import { type AuthProviderStatusResponse, getAuthProvidersContract } from '@/lib/api/contracts/auth'
2020
import { client } from '@/lib/auth/auth-client'
21-
import { getEnv, isFalsy, isTruthy } from '@/lib/core/config/env'
21+
import { getEnv, isFalsy } from '@/lib/core/config/env'
22+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
2223
import { captureClientEvent } from '@/lib/posthog/client'
2324
import type { PostHogEventMap } from '@/lib/posthog/events'
2425
import { getBrandConfig } from '@/ee/whitelabeling'
@@ -75,7 +76,7 @@ export function AuthModal({ children, defaultView = 'login', source }: AuthModal
7576
fetchProviderStatus().then(setProviderStatus)
7677
}, [])
7778

78-
const ssoEnabled = isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED'))
79+
const ssoEnabled = isSsoEnabled
7980
const emailEnabled = !isFalsy(getEnv('NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED'))
8081

8182
/**

apps/sim/app/workspace/[workspaceId]/files/components/share-modal/share-modal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { Send } from '@sim/emcn/icons'
1616
import { generateShortId } from '@sim/utils/id'
1717
import { GeneratedPasswordInput } from '@/components/ui'
1818
import type { ShareAuthType, ShareRecord } from '@/lib/api/contracts/public-shares'
19-
import { getEnv, isTruthy } from '@/lib/core/config/env'
19+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
2020
import { getBaseUrl } from '@/lib/core/utils/urls'
2121
import { quickValidateEmail } from '@/lib/messaging/email/validation'
2222
import { useFileShare, useUpsertFileShare } from '@/hooks/queries/public-shares'
@@ -91,7 +91,7 @@ export function ShareModal({
9191
const isAuthTypeAllowed = (mode: ShareAuthType) =>
9292
allowedAuthTypes === null || allowedAuthTypes.includes(mode)
9393

94-
const ssoEnabled = isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED')) || savedAccessMode === 'sso'
94+
const ssoEnabled = isSsoEnabled || savedAccessMode === 'sso'
9595
const candidateAuthTypes: ShareAuthType[] = [
9696
'public',
9797
'password',

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/chat/chat.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { getErrorMessage } from '@sim/utils/errors'
2222
import { normalizeEmail } from '@sim/utils/string'
2323
import { AlertTriangle, Check } from 'lucide-react'
2424
import { GeneratedPasswordInput } from '@/components/ui'
25-
import { getEnv, isTruthy } from '@/lib/core/config/env'
25+
import { isSsoEnabled } from '@/lib/core/config/env-flags'
2626
import { getBaseUrl, getEmailDomain } from '@/lib/core/utils/urls'
2727
import { quickValidateEmail } from '@/lib/messaging/email/validation'
2828
import { OutputSelect } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/chat/components/output-select/output-select'
@@ -713,9 +713,7 @@ function AuthSelector({
713713
const allowedAuthTypes = permissionConfig.allowedChatDeployAuthTypes
714714

715715
const ssoAvailable =
716-
isTruthy(getEnv('NEXT_PUBLIC_SSO_ENABLED')) ||
717-
savedAuthType === 'sso' ||
718-
(allowedAuthTypes?.includes('sso') ?? false)
716+
isSsoEnabled || savedAuthType === 'sso' || (allowedAuthTypes?.includes('sso') ?? false)
719717
const baseAuthOptions: AuthType[] = ssoAvailable
720718
? ['public', 'password', 'email', 'sso']
721719
: ['public', 'password', 'email']

apps/sim/ee/access-control/components/access-control.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { ArrowRight, Plus } from 'lucide-react'
1818
import { useParams } from 'next/navigation'
1919
import { useQueryState } from 'nuqs'
2020
import { isEnterprise } from '@/lib/billing/plan-helpers'
21-
import { getEnv, isTruthy } from '@/lib/core/config/env'
21+
import { isAccessControlEnabled } from '@/lib/core/config/env-flags'
2222
import {
2323
groupIdParam,
2424
groupIdUrlKeys,
@@ -73,9 +73,14 @@ export function AccessControl({ isOrganizationAdmin, organizationId }: AccessCon
7373
const { data: organizationWorkspaces = [], isPending: workspacesLoading } =
7474
useOrganizationWorkspaces(organizationId, !!organizationId && currentUserIsOrgAdmin)
7575

76-
const accessControlEnabledLocally = isTruthy(getEnv('NEXT_PUBLIC_ACCESS_CONTROL_ENABLED'))
76+
/**
77+
* Must be the resolved flag, not the raw `NEXT_PUBLIC_ACCESS_CONTROL_ENABLED`
78+
* read. The settings nav decides visibility from the same resolver, so
79+
* reading the bare var here let a deployment with only `ENTERPRISE_ENABLED`
80+
* set show the section and then refuse to manage it.
81+
*/
7782
const isEntitled =
78-
accessControlEnabledLocally ||
83+
isAccessControlEnabled ||
7984
!!userPermissionConfig?.entitled ||
8085
isEnterprise(organizationBillingData?.data?.subscriptionPlan)
8186
const canManage = isEntitled && currentUserIsOrgAdmin && !!organizationId

apps/sim/lib/auth/auth-client.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import {
1010
} from 'better-auth/client/plugins'
1111
import { createAuthClient } from 'better-auth/react'
1212
import type { auth } from '@/lib/auth'
13-
import { env } from '@/lib/core/config/env'
14-
import { isBillingEnabled, isOrganizationsEnabled } from '@/lib/core/config/env-flags'
13+
import { isBillingEnabled, isOrganizationsEnabled, isSsoEnabled } from '@/lib/core/config/env-flags'
1514
import { getBaseUrl, getBrowserOrigin } from '@/lib/core/utils/urls'
1615
import { SessionContext, type SessionHookResult } from '@/app/_shell/providers/session-provider'
1716

@@ -34,7 +33,7 @@ export const client = createAuthClient({
3433
]
3534
: []),
3635
...(isOrganizationsEnabled ? [organizationClient()] : []),
37-
...(env.NEXT_PUBLIC_SSO_ENABLED ? [ssoClient()] : []),
36+
...(isSsoEnabled ? [ssoClient()] : []),
3837
],
3938
})
4039

0 commit comments

Comments
 (0)