diff --git a/apps/login/app/(login)/register/idp/[provider]/success/page.tsx b/apps/login/app/(login)/idp/[provider]/success/page.tsx similarity index 71% rename from apps/login/app/(login)/register/idp/[provider]/success/page.tsx rename to apps/login/app/(login)/idp/[provider]/success/page.tsx index f7b55fcffe5..3779054fbec 100644 --- a/apps/login/app/(login)/register/idp/[provider]/success/page.tsx +++ b/apps/login/app/(login)/idp/[provider]/success/page.tsx @@ -1,6 +1,7 @@ import { ProviderSlug } from "#/lib/demos"; import { server } from "#/lib/zitadel"; import Alert, { AlertType } from "#/ui/Alert"; +import { createSessionForIdpAndUpdateCookie } from "#/utils/session"; import { AddHumanUserRequest, IDPInformation, @@ -96,21 +97,50 @@ export default async function Page({ return retrieveIDP(id, token) .then((information) => { if (information) { - return createUser(provider, information).catch((error) => { - throw new Error(error.details); - }); + console.log(information); + + // handle login + if (information.userId) { + return createSessionForIdpAndUpdateCookie( + information.userId, + { + idpIntentId: id, + idpIntentToken: token, + }, + undefined + ) + .then((session) => { + return ( +
+

Login successful

+
You have successfully been loggedIn!
+
+ ); + }) + .catch((error) => { + throw new Error(error.details); + }); + } else { + // handle register + + return createUser(provider, information) + .then((userId) => { + return ( +
+

Register successful

+
You have successfully been registered!
+
+ ); + }) + .catch((error) => { + throw new Error(error.details); + }); + } } else { throw new Error("Could not get user information."); } }) - .then((userId) => { - return ( -
-

Register successful

-
You have successfully been registered!
-
- ); - }) + .catch((error: Error) => { return (
diff --git a/apps/login/app/(login)/register/idp/page.tsx b/apps/login/app/(login)/idp/page.tsx similarity index 100% rename from apps/login/app/(login)/register/idp/page.tsx rename to apps/login/app/(login)/idp/page.tsx diff --git a/apps/login/app/(login)/loginname/page.tsx b/apps/login/app/(login)/loginname/page.tsx index 98ae5535681..3a80fc3b7c9 100644 --- a/apps/login/app/(login)/loginname/page.tsx +++ b/apps/login/app/(login)/loginname/page.tsx @@ -1,5 +1,31 @@ -import { getLoginSettings, server } from "#/lib/zitadel"; +import { + getLegalAndSupportSettings, + getLoginSettings, + server, +} from "#/lib/zitadel"; +import { SignInWithIDP } from "#/ui/SignInWithIDP"; import UsernameForm from "#/ui/UsernameForm"; +import { + GetActiveIdentityProvidersResponse, + IdentityProvider, + ZitadelServer, + settings, +} from "@zitadel/server"; + +function getIdentityProviders( + server: ZitadelServer, + orgId?: string +): Promise { + const settingsService = settings.getSettings(server); + return settingsService + .getActiveIdentityProviders( + orgId ? { ctx: { orgId } } : { ctx: { instance: true } }, + {} + ) + .then((resp: GetActiveIdentityProvidersResponse) => { + return resp.identityProviders; + }); +} export default async function Page({ searchParams, @@ -12,6 +38,14 @@ export default async function Page({ const submit: boolean = searchParams?.submit === "true"; const loginSettings = await getLoginSettings(server, organization); + const legal = await getLegalAndSupportSettings(server); + + // TODO if org idps should be shown replace emptystring with the orgId. + const identityProviders = await getIdentityProviders(server, ""); + + const host = process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : "http://localhost:3000"; return (
@@ -25,6 +59,13 @@ export default async function Page({ organization={organization} submit={submit} /> + + {legal && identityProviders && process.env.ZITADEL_API_URL && ( + + )}
); } diff --git a/apps/login/app/(login)/login/route.ts b/apps/login/app/login/route.ts similarity index 100% rename from apps/login/app/(login)/login/route.ts rename to apps/login/app/login/route.ts diff --git a/apps/login/lib/zitadel.ts b/apps/login/lib/zitadel.ts index e075a43a80b..4fcea77c020 100644 --- a/apps/login/lib/zitadel.ts +++ b/apps/login/lib/zitadel.ts @@ -125,6 +125,23 @@ export async function createSession( ); } +export async function createSessionForUserIdAndIdpIntent( + server: ZitadelServer, + userId: string, + idpIntent: { + idpIntentId?: string | undefined; + idpIntentToken?: string | undefined; + } +): Promise { + const sessionService = session.getSession(server); + return sessionService.createSession( + { + checks: { user: { userId }, idpIntent }, + }, + {} + ); +} + export async function setSession( server: ZitadelServer, sessionId: string, diff --git a/apps/login/ui/SessionItem.tsx b/apps/login/ui/SessionItem.tsx index f8f343124b9..f37be1196b7 100644 --- a/apps/login/ui/SessionItem.tsx +++ b/apps/login/ui/SessionItem.tsx @@ -42,8 +42,12 @@ export default function SessionItem({ const validPassword = session?.factors?.password?.verifiedAt; const validPasskey = session?.factors?.webAuthN?.verifiedAt; + const stillValid = session.expirationDate + ? session.expirationDate > new Date() + : true; - const validUser = validPassword || validPasskey; + const validDate = validPassword || validPasskey; + const validUser = (validPassword || validPasskey) && stillValid; return ( {validUser && ( - {moment(new Date(validUser)).fromNow()} + {validDate && moment(new Date(validDate)).fromNow()} )}
diff --git a/apps/login/ui/SignInWithIDP.tsx b/apps/login/ui/SignInWithIDP.tsx index a7788415940..628c4818913 100644 --- a/apps/login/ui/SignInWithIDP.tsx +++ b/apps/login/ui/SignInWithIDP.tsx @@ -40,8 +40,8 @@ export function SignInWithIDP({ }, body: JSON.stringify({ idpId, - successUrl: `${host}/register/idp/${provider}/success`, - failureUrl: `${host}/register/idp/${provider}/failure`, + successUrl: `${host}/idp/${provider}/success`, + failureUrl: `${host}/idp/${provider}/failure`, }), }); diff --git a/apps/login/utils/session.ts b/apps/login/utils/session.ts index d40fc8ec55b..99aad8abc49 100644 --- a/apps/login/utils/session.ts +++ b/apps/login/utils/session.ts @@ -1,4 +1,10 @@ -import { createSession, getSession, server, setSession } from "#/lib/zitadel"; +import { + createSession, + createSessionForUserIdAndIdpIntent, + getSession, + server, + setSession, +} from "#/lib/zitadel"; import { SessionCookie, addSessionToCookie, @@ -49,6 +55,50 @@ export async function createSessionAndUpdateCookie( } } +export async function createSessionForIdpAndUpdateCookie( + userId: string, + idpIntent: { + idpIntentId?: string | undefined; + idpIntentToken?: string | undefined; + }, + authRequestId: string | undefined +): Promise { + const createdSession = await createSessionForUserIdAndIdpIntent( + server, + userId, + idpIntent + ); + + if (createdSession) { + return getSession( + server, + createdSession.sessionId, + createdSession.sessionToken + ).then((response) => { + if (response?.session && response.session?.factors?.user?.loginName) { + const sessionCookie: SessionCookie = { + id: createdSession.sessionId, + token: createdSession.sessionToken, + changeDate: response.session.changeDate?.toString() ?? "", + loginName: response.session?.factors?.user?.loginName ?? "", + }; + + if (authRequestId) { + sessionCookie.authRequestId = authRequestId; + } + + return addSessionToCookie(sessionCookie).then(() => { + return response.session as Session; + }); + } else { + throw "could not get session or session does not have loginName"; + } + }); + } else { + throw "Could not create session"; + } +} + export type SessionWithChallenges = Session & { challenges: Challenges | undefined; };