diff --git a/apps/login/src/app/api/passkeys/verify/route.ts b/apps/login/src/app/api/passkeys/verify/route.ts index 064ba6e77a3..ea25a9ba5f0 100644 --- a/apps/login/src/app/api/passkeys/verify/route.ts +++ b/apps/login/src/app/api/passkeys/verify/route.ts @@ -18,14 +18,19 @@ export async function POST(request: NextRequest) { const session = await getSession(sessionCookie.id, sessionCookie.token); const userId = session?.session?.factors?.user?.id; - + console.log("payload", { + passkeyId, + passkeyName, + publicKeyCredential, + userId, + }); if (userId) { - return verifyPasskeyRegistration( + return verifyPasskeyRegistration({ passkeyId, passkeyName, publicKeyCredential, userId, - ) + }) .then((resp) => { return NextResponse.json(resp); }) diff --git a/apps/login/src/app/api/u2f/verify/route.ts b/apps/login/src/app/api/u2f/verify/route.ts index a842c8065c8..87f0a94d158 100644 --- a/apps/login/src/app/api/u2f/verify/route.ts +++ b/apps/login/src/app/api/u2f/verify/route.ts @@ -22,12 +22,15 @@ export async function POST(request: NextRequest) { const userId = session?.session?.factors?.user?.id; if (userId) { - const req: PlainMessage = { + let req: PlainMessage = { publicKeyCredential, u2fId, userId, tokenName: passkeyName, }; + + req = VerifyU2FRegistrationRequest.fromJson(request as any); + return verifyU2FRegistration(req) .then((resp) => { return NextResponse.json(resp); diff --git a/apps/login/src/lib/zitadel.ts b/apps/login/src/lib/zitadel.ts index d5ed5a89835..f075cc88a2f 100644 --- a/apps/login/src/lib/zitadel.ts +++ b/apps/login/src/lib/zitadel.ts @@ -12,6 +12,7 @@ import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb"; import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb"; import { RetrieveIdentityProviderIntentRequest, + VerifyPasskeyRegistrationRequest, VerifyU2FRegistrationRequest, } from "@zitadel/proto/zitadel/user/v2/user_service_pb"; import { IDPInformation } from "@zitadel/proto/zitadel/user/v2/idp_pb"; @@ -482,24 +483,11 @@ export async function getActiveIdentityProviders(orgId?: string) { * @returns the newly set email */ export async function verifyPasskeyRegistration( - passkeyId: string, - passkeyName: string, - publicKeyCredential: - | { - [key: string]: any; - } - | undefined, - userId: string, + request: PartialMessage, ) { - return userService.verifyPasskeyRegistration( - { - passkeyId, - passkeyName, - publicKeyCredential, - userId, - }, - {}, - ); + // TODO: find a better way to handle this + request = VerifyPasskeyRegistrationRequest.fromJson(request as any); + return userService.verifyPasskeyRegistration(request, {}); } /** diff --git a/apps/login/src/middleware.ts b/apps/login/src/middleware.ts index 982d5f5b150..965150efbcd 100644 --- a/apps/login/src/middleware.ts +++ b/apps/login/src/middleware.ts @@ -18,11 +18,14 @@ export function middleware(request: NextRequest) { requestHeaders.set("x-zitadel-login-client", SERVICE_USER_ID); // this is a workaround for the next.js server not forwarding the host header - requestHeaders.set("x-zitadel-forwarded", `host="${request.nextUrl.host}"`); - // requestHeaders.set("x-zitadel-public-host", `${request.nextUrl.host}`); + // requestHeaders.set("x-zitadel-forwarded", `host="${request.nextUrl.host}"`); + requestHeaders.set("x-zitadel-public-host", `${request.nextUrl.host}`); // this is a workaround for the next.js server not forwarding the host header - // requestHeaders.set("x-zitadel-instance-host", `${INSTANCE}`); + requestHeaders.set( + "x-zitadel-instance-host", + `${INSTANCE}`.replace("https://", ""), + ); const responseHeaders = new Headers(); responseHeaders.set("Access-Control-Allow-Origin", "*"); diff --git a/apps/login/src/ui/LoginPasskey.tsx b/apps/login/src/ui/LoginPasskey.tsx index fce8ecd8ecb..c29d9846d97 100644 --- a/apps/login/src/ui/LoginPasskey.tsx +++ b/apps/login/src/ui/LoginPasskey.tsx @@ -8,6 +8,7 @@ import Alert from "./Alert"; import { Spinner } from "./Spinner"; import BackButton from "./BackButton"; import { Checks } from "@zitadel/proto/zitadel/session/v2/session_service_pb"; +import { RequestChallenges } from "@zitadel/proto/zitadel/session/v2/challenge_pb"; // either loginName or sessionId must be provided type Props = { @@ -78,7 +79,7 @@ export default function LoginPasskey({ loginName, sessionId, organization, - challenges: { + challenges: RequestChallenges.fromJson({ webAuthN: { domain: "", // USER_VERIFICATION_REQUIREMENT_UNSPECIFIED = 0; @@ -87,7 +88,7 @@ export default function LoginPasskey({ // USER_VERIFICATION_REQUIREMENT_DISCOURAGED = 3; - mfa userVerificationRequirement: userVerificationRequirement, }, - }, + }), authRequestId, }), }); diff --git a/apps/login/src/ui/RegisterPasskey.tsx b/apps/login/src/ui/RegisterPasskey.tsx index 4ad72b583ba..6b2bdb1fb66 100644 --- a/apps/login/src/ui/RegisterPasskey.tsx +++ b/apps/login/src/ui/RegisterPasskey.tsx @@ -92,7 +92,7 @@ export default function RegisterPasskey({ return submitRegister().then((resp: RegisterPasskeyResponse) => { const passkeyId = resp.passkeyId; const options: CredentialCreationOptions = - (resp.publicKeyCredentialCreationOptions?.toJson() as CredentialCreationOptions) ?? + (resp.publicKeyCredentialCreationOptions as CredentialCreationOptions) ?? {}; if (options?.publicKey) { @@ -143,6 +143,7 @@ export default function RegisterPasskey({ ), }, }; + return submitVerify(passkeyId, "", data, sessionId).then(() => { const params = new URLSearchParams(); @@ -194,19 +195,32 @@ export default function RegisterPasskey({ type="button" variant={ButtonVariants.Secondary} onClick={() => { - const params = new URLSearchParams(); if (authRequestId) { - params.set("authRequest", authRequestId); - } - if (sessionId) { - params.set("sessionId", sessionId); - } + const params = new URLSearchParams({ + authRequest: authRequestId, + }); - if (organization) { - params.set("organization", organization); - } + if (sessionId) { + params.set("sessionId", sessionId); + } - router.push("/login?" + params); + if (organization) { + params.set("organization", organization); + } + + router.push("/login?" + params); + } else { + const params = new URLSearchParams(); + + if (sessionId) { + params.append("sessionId", sessionId); + } + if (organization) { + params.append("organization", organization); + } + + router.push("/signedin?" + params); + } }} > skip diff --git a/apps/login/src/ui/RegisterU2F.tsx b/apps/login/src/ui/RegisterU2F.tsx index eebbbe87b29..01081cd5eed 100644 --- a/apps/login/src/ui/RegisterU2F.tsx +++ b/apps/login/src/ui/RegisterU2F.tsx @@ -90,7 +90,7 @@ export default function RegisterU2F({ return submitRegister().then((resp: RegisterU2FResponse) => { const u2fId = resp.u2fId; const options: CredentialCreationOptions = - (resp.publicKeyCredentialCreationOptions?.toJson() as CredentialCreationOptions) ?? + (resp.publicKeyCredentialCreationOptions as CredentialCreationOptions) ?? {}; if (options.publicKey) { diff --git a/apps/login/src/ui/SessionItem.tsx b/apps/login/src/ui/SessionItem.tsx index 8f68916d099..f036fd01392 100644 --- a/apps/login/src/ui/SessionItem.tsx +++ b/apps/login/src/ui/SessionItem.tsx @@ -121,11 +121,12 @@ export default function SessionItem({ + onClick={(event) => { + event.preventDefault(); clearSession(session.id).then(() => { reload(); - }) - } + }); + }} /> diff --git a/apps/login/src/utils/session.ts b/apps/login/src/utils/session.ts index 7a2a6853a46..c9b1db12f29 100644 --- a/apps/login/src/utils/session.ts +++ b/apps/login/src/utils/session.ts @@ -38,7 +38,6 @@ export async function createSessionAndUpdateCookie( ? { user: { search: { case: "loginName", value: loginName } }, password: { password }, - // totp: { code: totpCode }, } : { user: { search: { case: "loginName", value: loginName } } }, challenges, @@ -50,7 +49,7 @@ export async function createSessionAndUpdateCookie( createdSession.sessionToken, ).then((response) => { if (response?.session && response.session?.factors?.user?.loginName) { - const sessionCookie: any = { + const sessionCookie: CustomCookieData = { id: createdSession.sessionId, token: createdSession.sessionToken, creationDate: `${response.session.creationDate?.toDate().getTime() ?? ""}`, @@ -103,7 +102,7 @@ export async function createSessionForUserIdAndUpdateCookie( createdSession.sessionToken, ).then((response) => { if (response?.session && response.session?.factors?.user?.loginName) { - const sessionCookie: any = { + const sessionCookie: CustomCookieData = { id: createdSession.sessionId, token: createdSession.sessionToken, creationDate: `${response.session.creationDate?.toDate().getTime() ?? ""}`, @@ -153,7 +152,7 @@ export async function createSessionForIdpAndUpdateCookie( createdSession.sessionToken, ).then((response) => { if (response?.session && response.session?.factors?.user?.loginName) { - const sessionCookie: any = { + const sessionCookie: CustomCookieData = { id: createdSession.sessionId, token: createdSession.sessionToken, creationDate: `${response.session.creationDate?.toDate().getTime() ?? ""}`, diff --git a/packages/zitadel-react/src/components/SignInWithAzureAD.tsx b/packages/zitadel-react/src/components/SignInWithAzureAD.tsx index d9f7859bcfd..38acc645912 100644 --- a/packages/zitadel-react/src/components/SignInWithAzureAD.tsx +++ b/packages/zitadel-react/src/components/SignInWithAzureAD.tsx @@ -2,39 +2,20 @@ import { ReactNode, forwardRef } from "react"; import { SignInWithIdentityProviderProps } from "./SignInWith"; +import { IdpButtonClasses } from "./classes"; -export const SignInWithAzureAD = forwardRef< - HTMLButtonElement, - SignInWithIdentityProviderProps ->( +export const SignInWithAzureAD = forwardRef( ({ children, className = "", name = "", ...props }, ref): ReactNode => ( - ), ); diff --git a/packages/zitadel-react/src/components/SignInWithGithub.tsx b/packages/zitadel-react/src/components/SignInWithGithub.tsx index d04f9b5fc0c..435459def55 100644 --- a/packages/zitadel-react/src/components/SignInWithGithub.tsx +++ b/packages/zitadel-react/src/components/SignInWithGithub.tsx @@ -2,18 +2,11 @@ import { ReactNode, forwardRef } from "react"; import { SignInWithIdentityProviderProps } from "./SignInWith"; +import { IdpButtonClasses } from "./classes"; -export const SignInWithGithub = forwardRef< - HTMLButtonElement, - SignInWithIdentityProviderProps ->( +export const SignInWithGithub = forwardRef( ({ children, className = "", name = "", ...props }, ref): ReactNode => ( - ), ); diff --git a/packages/zitadel-react/src/components/SignInWithGitlab.tsx b/packages/zitadel-react/src/components/SignInWithGitlab.tsx index 62b4d04c343..ffb1d09c49c 100644 --- a/packages/zitadel-react/src/components/SignInWithGitlab.tsx +++ b/packages/zitadel-react/src/components/SignInWithGitlab.tsx @@ -1,24 +1,12 @@ import { ReactNode, forwardRef } from "react"; import { SignInWithIdentityProviderProps } from "./SignInWith"; +import { IdpButtonClasses } from "./classes"; -export const SignInWithGitlab = forwardRef< - HTMLButtonElement, - SignInWithIdentityProviderProps ->( +export const SignInWithGitlab = forwardRef( ({ children, className = "", name = "", ...props }, ref): ReactNode => ( - ), ); diff --git a/packages/zitadel-react/src/components/SignInWithGoogle.tsx b/packages/zitadel-react/src/components/SignInWithGoogle.tsx index e3dc0c85965..af2dc40d26d 100644 --- a/packages/zitadel-react/src/components/SignInWithGoogle.tsx +++ b/packages/zitadel-react/src/components/SignInWithGoogle.tsx @@ -1,24 +1,12 @@ import { ReactNode, forwardRef } from "react"; import { SignInWithIdentityProviderProps } from "./SignInWith"; +import { IdpButtonClasses } from "./classes"; -export const SignInWithGoogle = forwardRef< - HTMLButtonElement, - SignInWithIdentityProviderProps ->( +export const SignInWithGoogle = forwardRef( ({ children, className = "", name = "", ...props }, ref): ReactNode => ( - ), ); diff --git a/packages/zitadel-react/src/components/classes.ts b/packages/zitadel-react/src/components/classes.ts new file mode 100644 index 00000000000..11216a561c4 --- /dev/null +++ b/packages/zitadel-react/src/components/classes.ts @@ -0,0 +1,2 @@ +export const IdpButtonClasses = + "transition-all ztdl-w-full ztdl-cursor-pointer ztdl-flex ztdl-flex-row ztdl-items-center bg-background-light-400 text-text-light-500 dark:bg-background-dark-500 dark:text-text-dark-500 border border-divider-light hover:border-black dark:border-divider-dark hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500 outline-none rounded-md px-4 text-sm";