login with idp

This commit is contained in:
peintnermax
2024-03-15 17:21:21 +01:00
parent 952a1c85be
commit 7cd59d8c6b
8 changed files with 159 additions and 17 deletions

View File

@@ -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,13 +97,33 @@ export default async function Page({
return retrieveIDP(id, token)
.then((information) => {
if (information) {
return createUser(provider, information).catch((error) => {
console.log(information);
// handle login
if (information.userId) {
return createSessionForIdpAndUpdateCookie(
information.userId,
{
idpIntentId: id,
idpIntentToken: token,
},
undefined
)
.then((session) => {
return (
<div className="flex flex-col items-center space-y-4">
<h1>Login successful</h1>
<div>You have successfully been loggedIn!</div>
</div>
);
})
.catch((error) => {
throw new Error(error.details);
});
} else {
throw new Error("Could not get user information.");
}
})
// handle register
return createUser(provider, information)
.then((userId) => {
return (
<div className="flex flex-col items-center space-y-4">
@@ -111,6 +132,15 @@ export default async function Page({
</div>
);
})
.catch((error) => {
throw new Error(error.details);
});
}
} else {
throw new Error("Could not get user information.");
}
})
.catch((error: Error) => {
return (
<div className="flex flex-col items-center space-y-4">

View File

@@ -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<IdentityProvider[] | undefined> {
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 (
<div className="flex flex-col items-center space-y-4">
@@ -25,6 +59,13 @@ export default async function Page({
organization={organization}
submit={submit}
/>
{legal && identityProviders && process.env.ZITADEL_API_URL && (
<SignInWithIDP
host={host}
identityProviders={identityProviders}
></SignInWithIDP>
)}
</div>
);
}

View File

@@ -125,6 +125,23 @@ export async function createSession(
);
}
export async function createSessionForUserIdAndIdpIntent(
server: ZitadelServer,
userId: string,
idpIntent: {
idpIntentId?: string | undefined;
idpIntentToken?: string | undefined;
}
): Promise<CreateSessionResponse | undefined> {
const sessionService = session.getSession(server);
return sessionService.createSession(
{
checks: { user: { userId }, idpIntent },
},
{}
);
}
export async function setSession(
server: ZitadelServer,
sessionId: string,

View File

@@ -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 (
<Link
@@ -92,7 +96,7 @@ export default function SessionItem({
</span>
{validUser && (
<span className="text-xs opacity-80">
{moment(new Date(validUser)).fromNow()}
{validDate && moment(new Date(validDate)).fromNow()}
</span>
)}
</div>

View File

@@ -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`,
}),
});

View File

@@ -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<Session> {
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;
};