From 66c3a783cd9acccb4f7c353d3982fcfb0cc83ecc Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Mon, 3 Jul 2023 08:44:48 +0200 Subject: [PATCH] login submit passkey credential --- apps/login/app/api/session/route.ts | 6 +- apps/login/lib/zitadel.ts | 3 +- apps/login/ui/LoginPasskey.tsx | 117 ++++++++++++++------------- apps/login/utils/session.ts | 8 +- packages/zitadel-server/src/index.ts | 1 + 5 files changed, 74 insertions(+), 61 deletions(-) diff --git a/apps/login/app/api/session/route.ts b/apps/login/app/api/session/route.ts index a080fc101c1..0721e196c2e 100644 --- a/apps/login/app/api/session/route.ts +++ b/apps/login/app/api/session/route.ts @@ -1,11 +1,10 @@ -import { server, deleteSession, getSession, setSession } from "#/lib/zitadel"; +import { server, deleteSession } from "#/lib/zitadel"; import { SessionCookie, getMostRecentSessionCookie, getSessionCookieById, getSessionCookieByLoginName, removeSessionFromCookie, - updateSessionCookie, } from "#/utils/cookies"; import { createSessionAndUpdateCookie, @@ -38,7 +37,7 @@ export async function PUT(request: NextRequest) { const body = await request.json(); if (body) { - const { loginName, password, challenges } = body; + const { loginName, password, challenges, passkey } = body; const recentPromise: Promise = loginName ? getSessionCookieByLoginName(loginName).catch((error) => { @@ -57,6 +56,7 @@ export async function PUT(request: NextRequest) { recent.token, recent.loginName, password, + passkey, domain, challenges ).then((session) => { diff --git a/apps/login/lib/zitadel.ts b/apps/login/lib/zitadel.ts index 6e1ffae0552..ff3069bbaf1 100644 --- a/apps/login/lib/zitadel.ts +++ b/apps/login/lib/zitadel.ts @@ -116,6 +116,7 @@ export async function setSession( sessionToken: string, domain: string | undefined, password: string | undefined, + passkey: { credentialAssertionData: any } | undefined, challenges: ChallengeKind[] | undefined ): Promise { const sessionService = session.getSession(server); @@ -125,7 +126,7 @@ export async function setSession( ? sessionService.setSession( { ...payload, - checks: { password: { password } }, + checks: { password: { password }, passkey }, }, {} ) diff --git a/apps/login/ui/LoginPasskey.tsx b/apps/login/ui/LoginPasskey.tsx index b019e20900a..087296ab143 100644 --- a/apps/login/ui/LoginPasskey.tsx +++ b/apps/login/ui/LoginPasskey.tsx @@ -63,23 +63,16 @@ export default function LoginPasskey({ loginName, challenge }: Props) { return res.json(); } - async function submitLogin( - passkeyId: string, - passkeyName: string, - publicKeyCredential: any, - sessionId: string - ) { + async function submitLogin(data: any) { setLoading(true); - const res = await fetch("/api/passkeys/verify", { + const res = await fetch("/api/session", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ - passkeyId, - passkeyName, - publicKeyCredential, - sessionId, + loginName, + passkey: data, }), }); @@ -95,51 +88,65 @@ export default function LoginPasskey({ loginName, challenge }: Props) { async function submitLoginAndContinue(): Promise { console.log("login", publicKey); - navigator.credentials - .get({ - publicKey, - }) - .then((assertedCredential: any) => { - if (assertedCredential) { - let authData = new Uint8Array( - assertedCredential.response.authenticatorData - ); - let clientDataJSON = new Uint8Array( - assertedCredential.response.clientDataJSON - ); - let rawId = new Uint8Array(assertedCredential.rawId); - let sig = new Uint8Array(assertedCredential.response.signature); - let userHandle = new Uint8Array( - assertedCredential.response.userHandle - ); - let data = JSON.stringify({ - id: assertedCredential.id, - rawId: coerceToBase64Url(rawId, "rawId"), - type: assertedCredential.type, - response: { - authenticatorData: coerceToBase64Url(authData, "authData"), - clientDataJSON: coerceToBase64Url( - clientDataJSON, - "clientDataJSON" - ), - signature: coerceToBase64Url(sig, "sig"), - userHandle: coerceToBase64Url(userHandle, "userHandle"), - }, - }); - console.log(data); - // return submitLogin(passkeyId, "", data, sessionId); - } else { - setLoading(false); - setError("An error on retrieving passkey"); - return null; - } - }) - .catch((error) => { - console.error(error); - setLoading(false); - // setError(error); - return null; + if (publicKey) { + console.log(publicKey); + (publicKey as any).challenge = coerceToArrayBuffer( + (publicKey as any).challenge, + "publicKey.challenge" + ); + (publicKey as any).allowCredentials.map((listItem: any) => { + listItem.id = coerceToArrayBuffer( + listItem.id, + "publicKey.allowCredentials.id" + ); }); + console.log(publicKey); + navigator.credentials + .get({ + publicKey, + }) + .then((assertedCredential: any) => { + if (assertedCredential) { + let authData = new Uint8Array( + assertedCredential.response.authenticatorData + ); + let clientDataJSON = new Uint8Array( + assertedCredential.response.clientDataJSON + ); + let rawId = new Uint8Array(assertedCredential.rawId); + let sig = new Uint8Array(assertedCredential.response.signature); + let userHandle = new Uint8Array( + assertedCredential.response.userHandle + ); + let data = JSON.stringify({ + id: assertedCredential.id, + rawId: coerceToBase64Url(rawId, "rawId"), + type: assertedCredential.type, + response: { + authenticatorData: coerceToBase64Url(authData, "authData"), + clientDataJSON: coerceToBase64Url( + clientDataJSON, + "clientDataJSON" + ), + signature: coerceToBase64Url(sig, "sig"), + userHandle: coerceToBase64Url(userHandle, "userHandle"), + }, + }); + console.log(data); + return submitLogin(data); + } else { + setLoading(false); + setError("An error on retrieving passkey"); + return null; + } + }) + .catch((error) => { + console.error(error); + setLoading(false); + // setError(error); + return null; + }); + } } return ( diff --git a/apps/login/utils/session.ts b/apps/login/utils/session.ts index 9b52b99ede6..34a0506bde6 100644 --- a/apps/login/utils/session.ts +++ b/apps/login/utils/session.ts @@ -5,7 +5,7 @@ import { addSessionToCookie, updateSessionCookie, } from "./cookies"; -import { ChallengeKind, Session } from "@zitadel/server"; +import { ChallengeKind, Session, Challenges } from "@zitadel/server"; export async function createSessionAndUpdateCookie( loginName: string, @@ -51,20 +51,24 @@ export async function createSessionAndUpdateCookie( } } +export type SessionWithChallenges = Session & { challenges: Challenges[] }; + export async function setSessionAndUpdateCookie( sessionId: string, sessionToken: string, loginName: string, password: string | undefined, + passkey: { credentialAssertionData: any } | undefined, domain: string | undefined, challenges: ChallengeKind[] | undefined -): Promise { +): Promise { return setSession( server, sessionId, sessionToken, domain, password, + passkey, challenges ).then((updatedSession) => { if (updatedSession) { diff --git a/packages/zitadel-server/src/index.ts b/packages/zitadel-server/src/index.ts index 4fbca57026b..a8bf5cf7285 100644 --- a/packages/zitadel-server/src/index.ts +++ b/packages/zitadel-server/src/index.ts @@ -16,6 +16,7 @@ export { LoginSettings } from "./proto/server/zitadel/settings/v2alpha/login_set export { ChallengeKind, + Challenges, Challenges_Passkey, } from "./proto/server/zitadel/session/v2alpha/challenge";