From df7a4f826717e68f8ae37430be4b0724e766e26c Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 22 Jun 2026 12:08:46 -0400 Subject: [PATCH 1/4] feat: oauth autoredirect support --- docs/CONFIGURATION.md | 4 ++++ src/env.ts | 2 ++ src/pages/auth/signin.tsx | 13 ++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 5fc723d6..5f18c0e4 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -67,6 +67,10 @@ Used for magic-link login and invites. ### OAuth providers +#### Shared OAuth settings + +- `OAUTH_AUTO_REDIRECT`: Optional flag. When set to `true`, the sign-in page automatically redirects to the first configured OAuth provider. This applies to any configured OAuth provider, including Google, Authentik, Keycloak, and generic OIDC. + #### Google - `GOOGLE_CLIENT_ID` diff --git a/src/env.ts b/src/env.ts index 913ed31c..60043a5f 100644 --- a/src/env.ts +++ b/src/env.ts @@ -71,6 +71,7 @@ export const env = createEnv({ OIDC_CLIENT_SECRET: z.string().optional(), OIDC_WELL_KNOWN_URL: z.string().optional(), OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: z.boolean().default(false), + OAUTH_AUTO_REDIRECT: z.boolean().optional(), UPLOAD_MAX_FILE_SIZE_MB: z.coerce.number().int().positive().default(10), }, @@ -142,6 +143,7 @@ export const env = createEnv({ OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: Boolean( JSON.parse(process.env.OIDC_ALLOW_DANGEROUS_EMAIL_LINKING || 'false'), ), + OAUTH_AUTO_REDIRECT: 'true' === process.env.OAUTH_AUTO_REDIRECT, UPLOAD_MAX_FILE_SIZE_MB: process.env.UPLOAD_MAX_FILE_SIZE_MB ? Number(process.env.UPLOAD_MAX_FILE_SIZE_MB) : 10, diff --git a/src/pages/auth/signin.tsx b/src/pages/auth/signin.tsx index 35490494..c5e9e49c 100644 --- a/src/pages/auth/signin.tsx +++ b/src/pages/auth/signin.tsx @@ -59,7 +59,8 @@ const Home: NextPage<{ feedbackEmail: string; providers: ClientSafeProvider[]; callbackUrl?: string; -}> = ({ error, providers: serverProviders, feedbackEmail, callbackUrl }) => { + oauthAutoRedirect: boolean; +}> = ({ error, providers: serverProviders, feedbackEmail, callbackUrl, oauthAutoRedirect }) => { const { t } = useTranslation(); const [emailStatus, setEmailStatus] = useState<'idle' | 'sending' | 'success'>('idle'); const [showVerificationStep, setShowVerificationStep] = useState(false); @@ -110,6 +111,15 @@ const Home: NextPage<{ } }, [error, t]); + useEffect(() => { + if (oauthAutoRedirect && !showVerificationStep && providers.length > 0 && !isLoadingProviders) { + const oauthProvider = providers.find((provider) => 'oauth' === provider.type); + if (oauthProvider) { + void signIn(oauthProvider.id, { callbackUrl }); + } + } + }, [oauthAutoRedirect, showVerificationStep, providers, isLoadingProviders, callbackUrl]); + const onEmailSubmit = useCallback(async () => { setEmailStatus('sending'); const email = emailForm.getValues().email.toLowerCase(); @@ -293,6 +303,7 @@ export const getServerSideProps: GetServerSideProps = async (context) => { feedbackEmail: env.FEEDBACK_EMAIL ?? '', providers: Object.values(providers ?? {}), callbackUrl: callbackUrl && !Array.isArray(callbackUrl) ? callbackUrl : '', + oauthAutoRedirect: env.OAUTH_AUTO_REDIRECT, }, }; }; From ebc2da658045943698f3f6727e3c17aa739c5e80 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 1 Aug 2026 17:14:12 -0400 Subject: [PATCH 2/4] fix(auth): restrict automatic OAuth redirects Only auto-redirect when exactly one OAuth provider is configured and no other authentication providers are enabled. Warn at startup for invalid configurations and document the required environment setup. --- .env.example | 4 ++++ docs/CONFIGURATION.md | 2 +- src/env.ts | 2 +- src/pages/auth/signin.tsx | 12 +++++++----- src/server/auth.ts | 8 ++++++++ 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.env.example b/.env.example index 63817705..100d2712 100644 --- a/.env.example +++ b/.env.example @@ -83,6 +83,10 @@ PLAID_COUNTRY_CODES= PLAID_INTERVAL_IN_DAYS= +# Automatically redirect sign-in when exactly one OAuth provider is configured and no other +# authentication providers are enabled +OAUTH_AUTO_REDIRECT=false + # Google Provider : https://next-auth.js.org/providers/google GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index 5f18c0e4..258021b3 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -69,7 +69,7 @@ Used for magic-link login and invites. #### Shared OAuth settings -- `OAUTH_AUTO_REDIRECT`: Optional flag. When set to `true`, the sign-in page automatically redirects to the first configured OAuth provider. This applies to any configured OAuth provider, including Google, Authentik, Keycloak, and generic OIDC. +- `OAUTH_AUTO_REDIRECT`: Optional flag. When set to `true`, the sign-in page automatically redirects when exactly one OAuth provider is configured and no other authentication providers are enabled. This applies to Google, Authentik, Keycloak, and generic OIDC. #### Google diff --git a/src/env.ts b/src/env.ts index 60043a5f..318f0932 100644 --- a/src/env.ts +++ b/src/env.ts @@ -143,7 +143,7 @@ export const env = createEnv({ OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: Boolean( JSON.parse(process.env.OIDC_ALLOW_DANGEROUS_EMAIL_LINKING || 'false'), ), - OAUTH_AUTO_REDIRECT: 'true' === process.env.OAUTH_AUTO_REDIRECT, + OAUTH_AUTO_REDIRECT: Boolean(JSON.parse(process.env.OAUTH_AUTO_REDIRECT || 'false')), UPLOAD_MAX_FILE_SIZE_MB: process.env.UPLOAD_MAX_FILE_SIZE_MB ? Number(process.env.UPLOAD_MAX_FILE_SIZE_MB) : 10, diff --git a/src/pages/auth/signin.tsx b/src/pages/auth/signin.tsx index c5e9e49c..09f4fcfd 100644 --- a/src/pages/auth/signin.tsx +++ b/src/pages/auth/signin.tsx @@ -112,11 +112,13 @@ const Home: NextPage<{ }, [error, t]); useEffect(() => { - if (oauthAutoRedirect && !showVerificationStep && providers.length > 0 && !isLoadingProviders) { - const oauthProvider = providers.find((provider) => 'oauth' === provider.type); - if (oauthProvider) { - void signIn(oauthProvider.id, { callbackUrl }); - } + const oauthProviders = providers.filter((provider) => 'oauth' === provider.type); + const shouldAutoRedirect = + oauthAutoRedirect && 1 === oauthProviders.length && 1 === providers.length; + + const oauthProvider = oauthProviders[0]; + if (shouldAutoRedirect && oauthProvider && !showVerificationStep && !isLoadingProviders) { + void signIn(oauthProvider.id, { callbackUrl }); } }, [oauthAutoRedirect, showVerificationStep, providers, isLoadingProviders, callbackUrl]); diff --git a/src/server/auth.ts b/src/server/auth.ts index bbc73e30..f3951680 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -283,6 +283,14 @@ export function validateAuthEnv() { console.log('Validating auth env'); if (!process.env.SKIP_ENV_VALIDATION) { const providers = getProviders(); + const oauthProviders = providers.filter((provider) => 'oauth' === provider.type); + + if (env.OAUTH_AUTO_REDIRECT && (1 !== oauthProviders.length || 1 !== providers.length)) { + console.warn( + 'OAUTH_AUTO_REDIRECT is enabled, but automatic redirection will not happen until exactly one OAuth provider and no other authentication providers are configured.', + ); + } + if (0 === providers.length) { throw new Error( 'No authentication providers are configured, at least one is required. Learn more here: https://github.com/oss-apps/split-pro?tab=readme-ov-file#setting-up-the-environment', From 51753d6fa3ef86193e87929d5b4ef42ab2b1a27f Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 1 Aug 2026 17:37:38 -0400 Subject: [PATCH 3/4] fix(auth): prevent OAuth redirect retries after errors Skip automatic OAuth redirection when a sign-in error is present, preventing failed callbacks from restarting the OAuth flow. Show an error toast when the automatic sign-in promise rejects and include the translation function in the effect dependencies. --- src/pages/auth/signin.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/pages/auth/signin.tsx b/src/pages/auth/signin.tsx index 09f4fcfd..2e2cfe3d 100644 --- a/src/pages/auth/signin.tsx +++ b/src/pages/auth/signin.tsx @@ -113,14 +113,26 @@ const Home: NextPage<{ useEffect(() => { const oauthProviders = providers.filter((provider) => 'oauth' === provider.type); + // SessionRequired indicates an unauthenticated route redirect, not a failed sign-in. + const hasSignInError = Boolean(error && 'SessionRequired' !== error); const shouldAutoRedirect = - oauthAutoRedirect && 1 === oauthProviders.length && 1 === providers.length; + oauthAutoRedirect && !hasSignInError && 1 === oauthProviders.length && 1 === providers.length; const oauthProvider = oauthProviders[0]; if (shouldAutoRedirect && oauthProvider && !showVerificationStep && !isLoadingProviders) { - void signIn(oauthProvider.id, { callbackUrl }); + void signIn(oauthProvider.id, { callbackUrl }).catch(() => { + toast.error(t('errors.signin_error')); + }); } - }, [oauthAutoRedirect, showVerificationStep, providers, isLoadingProviders, callbackUrl]); + }, [ + oauthAutoRedirect, + error, + showVerificationStep, + providers, + isLoadingProviders, + callbackUrl, + t, + ]); const onEmailSubmit = useCallback(async () => { setEmailStatus('sending'); From b8727d5e8f291db6bd3c786007728450fa482448 Mon Sep 17 00:00:00 2001 From: Josh Date: Sun, 2 Aug 2026 12:42:38 -0400 Subject: [PATCH 4/4] fix(env): default OAuth auto-redirect to false Ensure OAUTH_AUTO_REDIRECT always resolves to a boolean during environment validation. --- src/env.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env.ts b/src/env.ts index 318f0932..8d91edf5 100644 --- a/src/env.ts +++ b/src/env.ts @@ -71,7 +71,7 @@ export const env = createEnv({ OIDC_CLIENT_SECRET: z.string().optional(), OIDC_WELL_KNOWN_URL: z.string().optional(), OIDC_ALLOW_DANGEROUS_EMAIL_LINKING: z.boolean().default(false), - OAUTH_AUTO_REDIRECT: z.boolean().optional(), + OAUTH_AUTO_REDIRECT: z.boolean().default(false), UPLOAD_MAX_FILE_SIZE_MB: z.coerce.number().int().positive().default(10), },