diff --git a/apps/login/src/components/idp-signin.tsx b/apps/login/src/components/idp-signin.tsx index 543cd64b2c..c2f3fe40b3 100644 --- a/apps/login/src/components/idp-signin.tsx +++ b/apps/login/src/components/idp-signin.tsx @@ -1,6 +1,6 @@ "use client"; -import { createNewSessionForIdp } from "@/lib/server/session"; +import { createNewSessionFromIdpIntent } from "@/lib/server/idp"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { Alert } from "./alert"; @@ -27,7 +27,7 @@ export function IdpSignin({ const router = useRouter(); useEffect(() => { - createNewSessionForIdp({ + createNewSessionFromIdpIntent({ userId, idpIntent: { idpIntentId, diff --git a/apps/login/src/lib/server/idp.ts b/apps/login/src/lib/server/idp.ts index ebb755987e..35eadc70f9 100644 --- a/apps/login/src/lib/server/idp.ts +++ b/apps/login/src/lib/server/idp.ts @@ -1,7 +1,14 @@ "use server"; -import { startIdentityProviderFlow } from "@/lib/zitadel"; +import { + getLoginSettings, + getUserByID, + startIdentityProviderFlow, +} from "@/lib/zitadel"; import { headers } from "next/headers"; +import { getNextUrl } from "../client"; +import { checkEmailVerification } from "../verify-helper"; +import { createSessionForIdpAndUpdateCookie } from "./cookie"; export type StartIDPFlowCommand = { idpId: string; @@ -32,3 +39,82 @@ export async function startIDPFlow(command: StartIDPFlowCommand) { } }); } + +type CreateNewSessionCommand = { + userId: string; + idpIntent: { + idpIntentId: string; + idpIntentToken: string; + }; + loginName?: string; + password?: string; + organization?: string; + authRequestId?: string; +}; + +export async function createNewSessionFromIdpIntent( + command: CreateNewSessionCommand, +) { + if (!command.userId || !command.idpIntent) { + throw new Error("No userId or loginName provided"); + } + + const userResponse = await getUserByID(command.userId); + + if (!userResponse || !userResponse.user) { + return { error: "Could not find user" }; + } + + const loginSettings = await getLoginSettings( + userResponse.user.details?.resourceOwner, + ); + + const session = await createSessionForIdpAndUpdateCookie( + command.userId, + command.idpIntent, + command.authRequestId, + loginSettings?.externalLoginCheckLifetime, + ); + + if (!session || !session.factors?.user) { + return { error: "Could not create session" }; + } + + const humanUser = + userResponse.user.type.case === "human" + ? userResponse.user.type.value + : undefined; + + // check to see if user was verified + const emailVerificationCheck = checkEmailVerification( + session, + humanUser, + command.organization, + command.authRequestId, + ); + + if (emailVerificationCheck?.redirect) { + return emailVerificationCheck; + } + + // TODO: check if user has MFA methods + // checkMFAFactors(session, loginSettings, authMethods, organization, authRequestId); + + const url = await getNextUrl( + command.authRequestId && session.id + ? { + sessionId: session.id, + authRequestId: command.authRequestId, + organization: session.factors.user.organizationId, + } + : { + loginName: session.factors.user.loginName, + organization: session.factors.user.organizationId, + }, + loginSettings?.defaultRedirectUri, + ); + + if (url) { + return { redirect: url }; + } +} diff --git a/apps/login/src/lib/server/passkeys.ts b/apps/login/src/lib/server/passkeys.ts index f34702a61e..ca27d310f3 100644 --- a/apps/login/src/lib/server/passkeys.ts +++ b/apps/login/src/lib/server/passkeys.ts @@ -175,7 +175,16 @@ export async function sendPasskey(command: SendPasskeyCommand) { ? userResponse.user.type.value : undefined; - checkEmailVerification(session, humanUser, organization, authRequestId); + const emailVerificationCheck = checkEmailVerification( + session, + humanUser, + organization, + authRequestId, + ); + + if (emailVerificationCheck?.redirect) { + return emailVerificationCheck; + } const url = authRequestId && session.id diff --git a/apps/login/src/lib/server/password.ts b/apps/login/src/lib/server/password.ts index c89cf02cea..68206f06a3 100644 --- a/apps/login/src/lib/server/password.ts +++ b/apps/login/src/lib/server/password.ts @@ -142,26 +142,34 @@ export async function sendPassword(command: UpdateSessionCommand) { const humanUser = user.type.case === "human" ? user.type.value : undefined; // check if the user has to change password first - checkPasswordChangeRequired( + const passwordChangedCheck = checkPasswordChangeRequired( session, humanUser, command.organization, command.authRequestId, ); + if (passwordChangedCheck?.redirect) { + return passwordChangedCheck; + } + // throw error if user is in initial state here and do not continue if (user.state === UserState.INITIAL) { return { error: "Initial User not supported" }; } // check to see if user was verified - checkEmailVerification( + const emailVerificationCheck = checkEmailVerification( session, humanUser, command.organization, command.authRequestId, ); + if (emailVerificationCheck?.redirect) { + return emailVerificationCheck; + } + // if password, check if user has MFA methods let authMethods; if (command.checks && command.checks.password && session.factors?.user?.id) { diff --git a/apps/login/src/lib/server/session.ts b/apps/login/src/lib/server/session.ts index 566f4818d3..70bc18f6d5 100644 --- a/apps/login/src/lib/server/session.ts +++ b/apps/login/src/lib/server/session.ts @@ -1,13 +1,9 @@ "use server"; -import { - createSessionForIdpAndUpdateCookie, - setSessionAndUpdateCookie, -} from "@/lib/server/cookie"; +import { setSessionAndUpdateCookie } from "@/lib/server/cookie"; import { deleteSession, getLoginSettings, - getUserByID, listAuthenticationMethodTypes, } from "@/lib/zitadel"; import { Duration } from "@zitadel/client"; @@ -22,81 +18,6 @@ import { getSessionCookieByLoginName, removeSessionFromCookie, } from "../cookies"; -import { checkPasswordChangeRequired } from "../verify-helper"; - -type CreateNewSessionCommand = { - userId: string; - idpIntent: { - idpIntentId: string; - idpIntentToken: string; - }; - loginName?: string; - password?: string; - authRequestId?: string; -}; - -export async function createNewSessionForIdp(options: CreateNewSessionCommand) { - const { userId, idpIntent, authRequestId } = options; - - if (!userId || !idpIntent) { - throw new Error("No userId or loginName provided"); - } - - const userResponse = await getUserByID(userId); - - if (!userResponse || !userResponse.user) { - return { error: "Could not find user" }; - } - - const loginSettings = await getLoginSettings( - userResponse.user.details?.resourceOwner, - ); - - const session = await createSessionForIdpAndUpdateCookie( - userId, - idpIntent, - authRequestId, - loginSettings?.externalLoginCheckLifetime, - ); - - if (!session || !session.factors?.user) { - return { error: "Could not create session" }; - } - - const humanUser = - userResponse.user.type.case === "human" - ? userResponse.user.type.value - : undefined; - - // check if the user has to change password first - checkPasswordChangeRequired( - session, - humanUser, - session.factors.user.organizationId, - authRequestId, - ); - - // TODO: check if user has MFA methods - // checkMFAFactors(session, loginSettings, authMethods, organization, authRequestId); - - const url = await getNextUrl( - authRequestId && session.id - ? { - sessionId: session.id, - authRequestId: authRequestId, - organization: session.factors.user.organizationId, - } - : { - loginName: session.factors.user.loginName, - organization: session.factors.user.organizationId, - }, - loginSettings?.defaultRedirectUri, - ); - - if (url) { - return { redirect: url }; - } -} export async function continueWithSession({ authRequestId, diff --git a/apps/login/src/lib/verify-helper.ts b/apps/login/src/lib/verify-helper.ts index ec88807c71..2161e08168 100644 --- a/apps/login/src/lib/verify-helper.ts +++ b/apps/login/src/lib/verify-helper.ts @@ -35,6 +35,11 @@ export function checkEmailVerification( organization?: string, authRequestId?: string, ) { + console.log( + humanUser?.email, + process.env.EMAIL_VERIFICATION, + process.env.EMAIL_VERIFICATION === "true", + ); if ( !humanUser?.email?.isVerified && process.env.EMAIL_VERIFICATION === "true"