diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/service/UserLicenseSettingsService.java b/app/proprietary/src/main/java/stirling/software/proprietary/service/UserLicenseSettingsService.java index 47c041f90b..aa794e6997 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/service/UserLicenseSettingsService.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/service/UserLicenseSettingsService.java @@ -354,6 +354,7 @@ public class UserLicenseSettingsService { return true; } + // todo: remove if (user != null) { log.info( "User {} is NOT grandfathered (isOauthGrandfathered={})", @@ -559,12 +560,6 @@ public class UserLicenseSettingsService { boolean hasPaid = (license == License.SERVER || license == License.ENTERPRISE); log.info("License check result: type={}, requiresPaid=true, hasPaid={}", license, hasPaid); - if (!hasPaid) { - log.warn( - "OAuth requires SERVER or ENTERPRISE license but found: {}. OAuth login will be blocked.", - license); - } - return hasPaid; } diff --git a/frontend/src/proprietary/auth/oauthTypes.ts b/frontend/src/proprietary/auth/oauthTypes.ts new file mode 100644 index 0000000000..2d38f1b3e5 --- /dev/null +++ b/frontend/src/proprietary/auth/oauthTypes.ts @@ -0,0 +1,24 @@ +/** + * Known OAuth providers with dedicated UI support. + * Custom providers are also supported - the backend determines availability. + */ +export const KNOWN_OAUTH_PROVIDERS = [ + 'github', + 'google', + 'apple', + 'azure', + 'keycloak', + 'cloudron', + 'authentik', + 'oidc', +] as const; + +export type KnownOAuthProvider = typeof KNOWN_OAUTH_PROVIDERS[number]; + +/** + * OAuth provider ID - can be any known provider or custom string. + * The backend configuration determines which providers are available. + * + * @example 'github' | 'google' | 'mycompany' | 'authentik' + */ +export type OAuthProvider = KnownOAuthProvider | (string & {}); diff --git a/frontend/src/proprietary/auth/springAuthClient.ts b/frontend/src/proprietary/auth/springAuthClient.ts index 1f54c5d2f7..646b711823 100644 --- a/frontend/src/proprietary/auth/springAuthClient.ts +++ b/frontend/src/proprietary/auth/springAuthClient.ts @@ -10,6 +10,7 @@ import apiClient from '@app/services/apiClient'; import { AxiosError } from 'axios'; import { BASE_PATH } from '@app/constants/app'; +import { type OAuthProvider } from '@app/auth/oauthTypes'; // Helper to extract error message from axios error function getErrorMessage(error: unknown, fallback: string): string { @@ -252,10 +253,10 @@ class SpringAuthClient { * This redirects to the Spring OAuth2 authorization endpoint * * @param params.provider - OAuth provider ID (e.g., 'github', 'google', 'authentik', 'mycompany') - * Can be any string - the backend determines available providers + * Can be any known provider or custom string - the backend determines available providers */ async signInWithOAuth(params: { - provider: string; + provider: OAuthProvider; options?: { redirectTo?: string; queryParams?: Record }; }): Promise<{ error: AuthError | null }> { try { diff --git a/frontend/src/proprietary/routes/Login.tsx b/frontend/src/proprietary/routes/Login.tsx index 46b95f98a5..cf6004e505 100644 --- a/frontend/src/proprietary/routes/Login.tsx +++ b/frontend/src/proprietary/routes/Login.tsx @@ -10,6 +10,7 @@ import AuthLayout from '@app/routes/authShared/AuthLayout'; import { useBackendProbe } from '@app/hooks/useBackendProbe'; import apiClient from '@app/services/apiClient'; import { BASE_PATH } from '@app/constants/app'; +import { type OAuthProvider } from '@app/auth/oauthTypes'; // Import login components import LoginHeader from '@app/routes/login/LoginHeader'; @@ -31,7 +32,7 @@ export default function Login() { const [showEmailForm, setShowEmailForm] = useState(false); const [email, setEmail] = useState(() => searchParams.get('email') ?? ''); const [password, setPassword] = useState(''); - const [enabledProviders, setEnabledProviders] = useState([]); + const [enabledProviders, setEnabledProviders] = useState([]); const [hasSSOProviders, setHasSSOProviders] = useState(false); const [_enableLogin, setEnableLogin] = useState(null); const backendProbe = useBackendProbe(); @@ -226,7 +227,7 @@ export default function Login() { ); } - const signInWithProvider = async (provider: string) => { + const signInWithProvider = async (provider: OAuthProvider) => { try { setIsSigningIn(true); setError(null); diff --git a/frontend/src/proprietary/routes/login/OAuthButtons.tsx b/frontend/src/proprietary/routes/login/OAuthButtons.tsx index aaa280519f..d62edfdc15 100644 --- a/frontend/src/proprietary/routes/login/OAuthButtons.tsx +++ b/frontend/src/proprietary/routes/login/OAuthButtons.tsx @@ -1,5 +1,6 @@ import { useTranslation } from 'react-i18next'; import { BASE_PATH } from '@app/constants/app'; +import { type OAuthProvider } from '@app/auth/oauthTypes'; // Debug flag to show all providers for UI testing // Set to true to see all SSO options regardless of backend configuration @@ -22,10 +23,10 @@ export const oauthProviderConfig: Record void + onProviderClick: (provider: OAuthProvider) => void isSubmitting: boolean layout?: 'vertical' | 'grid' | 'icons' - enabledProviders?: string[] // List of enabled provider IDs from backend + enabledProviders?: OAuthProvider[] // List of enabled provider IDs from backend } export default function OAuthButtons({ onProviderClick, isSubmitting, layout = 'vertical', enabledProviders = [] }: OAuthButtonsProps) {