set public key state

This commit is contained in:
Max Peintner
2023-06-30 15:32:41 +02:00
parent 9ba466387b
commit 02444814ef
5 changed files with 128 additions and 98 deletions

View File

@@ -60,7 +60,7 @@ export async function PUT(request: NextRequest) {
domain, domain,
challenges challenges
).then((session) => { ).then((session) => {
console.log(session.challenges); console.log(session);
return NextResponse.json({ return NextResponse.json({
sessionId: session.id, sessionId: session.id,
factors: session.factors, factors: session.factors,

View File

@@ -30,7 +30,7 @@
"clsx": "1.2.1", "clsx": "1.2.1",
"date-fns": "2.29.3", "date-fns": "2.29.3",
"moment": "^2.29.4", "moment": "^2.29.4",
"next": "13.4.2", "next": "13.4.7",
"next-themes": "^0.2.1", "next-themes": "^0.2.1",
"nice-grpc": "2.0.1", "nice-grpc": "2.0.1",
"react": "18.2.0", "react": "18.2.0",

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { ChallengeKind, Challenges_Passkey } from "@zitadel/server"; import { ChallengeKind, Challenges_Passkey } from "@zitadel/server";
import { coerceToArrayBuffer, coerceToBase64Url } from "#/utils/base64"; import { coerceToArrayBuffer, coerceToBase64Url } from "#/utils/base64";
@@ -15,12 +15,31 @@ type Props = {
export default function LoginPasskey({ loginName, challenge }: Props) { export default function LoginPasskey({ loginName, challenge }: Props) {
const [error, setError] = useState<string>(""); const [error, setError] = useState<string>("");
const [publicKey, setPublicKey] = useState();
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const router = useRouter(); const router = useRouter();
const initialized = useRef(false);
useEffect(() => { useEffect(() => {
updateSessionForChallenge(); if (!initialized.current) {
initialized.current = true;
updateSessionForChallenge()
.then((response) => {
const pK =
response.challenges.passkey.publicKeyCredentialRequestOptions
.publicKey;
if (pK) {
setPublicKey(pK);
} else {
setError("Could not request passkey challenge");
}
})
.catch((error) => {
setError(error);
});
}
}, []); }, []);
async function updateSessionForChallenge() { async function updateSessionForChallenge() {
@@ -38,7 +57,8 @@ export default function LoginPasskey({ loginName, challenge }: Props) {
setLoading(false); setLoading(false);
if (!res.ok) { if (!res.ok) {
throw new Error("Failed to load authentication methods"); const error = await res.json();
throw error.details.details;
} }
return res.json(); return res.json();
} }
@@ -74,52 +94,52 @@ export default function LoginPasskey({ loginName, challenge }: Props) {
} }
async function submitLoginAndContinue(): Promise<boolean | void> { async function submitLoginAndContinue(): Promise<boolean | void> {
// navigator.credentials console.log("login", publicKey);
// .get({ navigator.credentials
// publicKey: challenge.publicKeyCredentialRequestOptions, .get({
// }) publicKey,
// .then((assertedCredential: any) => { })
// if (assertedCredential) { .then((assertedCredential: any) => {
// let authData = new Uint8Array( if (assertedCredential) {
// assertedCredential.response.authenticatorData let authData = new Uint8Array(
// ); assertedCredential.response.authenticatorData
// let clientDataJSON = new Uint8Array( );
// assertedCredential.response.clientDataJSON let clientDataJSON = new Uint8Array(
// ); assertedCredential.response.clientDataJSON
// let rawId = new Uint8Array(assertedCredential.rawId); );
// let sig = new Uint8Array(assertedCredential.response.signature); let rawId = new Uint8Array(assertedCredential.rawId);
// let userHandle = new Uint8Array( let sig = new Uint8Array(assertedCredential.response.signature);
// assertedCredential.response.userHandle let userHandle = new Uint8Array(
// ); assertedCredential.response.userHandle
// let data = JSON.stringify({ );
// id: assertedCredential.id, let data = JSON.stringify({
// rawId: coerceToBase64Url(rawId, "rawId"), id: assertedCredential.id,
// type: assertedCredential.type, rawId: coerceToBase64Url(rawId, "rawId"),
// response: { type: assertedCredential.type,
// authenticatorData: coerceToBase64Url(authData, "authData"), response: {
// clientDataJSON: coerceToBase64Url( authenticatorData: coerceToBase64Url(authData, "authData"),
// clientDataJSON, clientDataJSON: coerceToBase64Url(
// "clientDataJSON" clientDataJSON,
// ), "clientDataJSON"
// signature: coerceToBase64Url(sig, "sig"), ),
// userHandle: coerceToBase64Url(userHandle, "userHandle"), signature: coerceToBase64Url(sig, "sig"),
// }, userHandle: coerceToBase64Url(userHandle, "userHandle"),
// }); },
// return submitLogin(passkeyId, "", data, sessionId); });
// } else { console.log(data);
// setLoading(false); // return submitLogin(passkeyId, "", data, sessionId);
// setError("An error on retrieving passkey"); } else {
// return null; setLoading(false);
// } setError("An error on retrieving passkey");
// }) return null;
// .catch((error) => { }
// console.error(error); })
// setLoading(false); .catch((error) => {
// // setError(error); console.error(error);
// return null; setLoading(false);
// }); // setError(error);
// } return null;
// return router.push(`/accounts`); });
} }
return ( return (
@@ -143,7 +163,7 @@ export default function LoginPasskey({ loginName, challenge }: Props) {
type="submit" type="submit"
className="self-end" className="self-end"
variant={ButtonVariants.Primary} variant={ButtonVariants.Primary}
disabled={loading} disabled={loading || !publicKey}
onClick={() => submitLoginAndContinue()} onClick={() => submitLoginAndContinue()}
> >
{loading && <Spinner className="h-5 w-5 mr-2" />} {loading && <Spinner className="h-5 w-5 mr-2" />}

View File

@@ -66,12 +66,12 @@ export async function setSessionAndUpdateCookie(
domain, domain,
password, password,
challenges challenges
).then((session) => { ).then((updatedSession) => {
if (session) { if (updatedSession) {
const sessionCookie: SessionCookie = { const sessionCookie: SessionCookie = {
id: sessionId, id: sessionId,
token: session.sessionToken, token: updatedSession.sessionToken,
changeDate: session.details?.changeDate?.toString() ?? "", changeDate: updatedSession.details?.changeDate?.toString() ?? "",
loginName: loginName, loginName: loginName,
}; };
@@ -81,13 +81,13 @@ export async function setSessionAndUpdateCookie(
const { session } = response; const { session } = response;
const newCookie: SessionCookie = { const newCookie: SessionCookie = {
id: sessionCookie.id, id: sessionCookie.id,
token: sessionCookie.token, token: updatedSession.sessionToken,
changeDate: session.changeDate?.toString() ?? "", changeDate: session.changeDate?.toString() ?? "",
loginName: session.factors?.user?.loginName ?? "", loginName: session.factors?.user?.loginName ?? "",
}; };
return updateSessionCookie(sessionCookie.id, newCookie).then(() => { return updateSessionCookie(sessionCookie.id, newCookie).then(() => {
return session; return { challenges: updatedSession.challenges, ...session };
}); });
} else { } else {
throw "could not get session or session does not have loginName"; throw "could not get session or session does not have loginName";

90
pnpm-lock.yaml generated
View File

@@ -50,7 +50,7 @@ importers:
lint-staged: 13.0.3 lint-staged: 13.0.3
make-dir-cli: 3.0.0 make-dir-cli: 3.0.0
moment: ^2.29.4 moment: ^2.29.4
next: 13.4.2 next: 13.4.7
next-themes: ^0.2.1 next-themes: ^0.2.1
nice-grpc: 2.0.1 nice-grpc: 2.0.1
postcss: 8.4.21 postcss: 8.4.21
@@ -78,8 +78,8 @@ importers:
clsx: 1.2.1 clsx: 1.2.1
date-fns: 2.29.3 date-fns: 2.29.3
moment: 2.29.4 moment: 2.29.4
next: 13.4.2_bteaqif5pz4zkv4h4kccxuyuxu next: 13.4.7_bteaqif5pz4zkv4h4kccxuyuxu
next-themes: 0.2.1_cmp7sjki5xcmfyvhcokzzink7a next-themes: 0.2.1_5v7kwk6wz2hvmegftnptprfjvm
nice-grpc: 2.0.1 nice-grpc: 2.0.1
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0_react@18.2.0 react-dom: 18.2.0_react@18.2.0
@@ -1315,8 +1315,8 @@ packages:
resolution: {integrity: sha512-FN50r/E+b8wuqyRjmGaqvqNDuWBWYWQiigfZ50KnSFH0f+AMQQyaZl+Zm2+CIpKk0fL9QxhLxOpTVA3xFHgFow==} resolution: {integrity: sha512-FN50r/E+b8wuqyRjmGaqvqNDuWBWYWQiigfZ50KnSFH0f+AMQQyaZl+Zm2+CIpKk0fL9QxhLxOpTVA3xFHgFow==}
dev: false dev: false
/@next/env/13.4.2: /@next/env/13.4.7:
resolution: {integrity: sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw==} resolution: {integrity: sha512-ZlbiFulnwiFsW9UV1ku1OvX/oyIPLtMk9p/nnvDSwI0s7vSoZdRtxXNsaO+ZXrLv/pMbXVGq4lL8TbY9iuGmVw==}
dev: false dev: false
/@next/eslint-plugin-next/13.4.5: /@next/eslint-plugin-next/13.4.5:
@@ -1352,8 +1352,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-darwin-arm64/13.4.2: /@next/swc-darwin-arm64/13.4.7:
resolution: {integrity: sha512-6BBlqGu3ewgJflv9iLCwO1v1hqlecaIH2AotpKfVUEzUxuuDNJQZ2a4KLb4MBl8T9/vca1YuWhSqtbF6ZuUJJw==} resolution: {integrity: sha512-VZTxPv1b59KGiv/pZHTO5Gbsdeoxcj2rU2cqJu03btMhHpn3vwzEK0gUSVC/XW96aeGO67X+cMahhwHzef24/w==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
@@ -1370,8 +1370,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-darwin-x64/13.4.2: /@next/swc-darwin-x64/13.4.7:
resolution: {integrity: sha512-iZuYr7ZvGLPjPmfhhMl0ISm+z8EiyLBC1bLyFwGBxkWmPXqdJ60mzuTaDSr5WezDwv0fz32HB7JHmRC6JVHSZg==} resolution: {integrity: sha512-gO2bw+2Ymmga+QYujjvDz9955xvYGrWofmxTq7m70b9pDPvl7aDFABJOZ2a8SRCuSNB5mXU8eTOmVVwyp/nAew==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
@@ -1406,8 +1406,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-linux-arm64-gnu/13.4.2: /@next/swc-linux-arm64-gnu/13.4.7:
resolution: {integrity: sha512-2xVabFtIge6BJTcJrW8YuUnYTuQjh4jEuRuS2mscyNVOj6zUZkom3CQg+egKOoS+zh2rrro66ffSKIS+ztFJTg==} resolution: {integrity: sha512-6cqp3vf1eHxjIDhEOc7Mh/s8z1cwc/l5B6ZNkOofmZVyu1zsbEM5Hmx64s12Rd9AYgGoiCz4OJ4M/oRnkE16/Q==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
@@ -1424,8 +1424,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-linux-arm64-musl/13.4.2: /@next/swc-linux-arm64-musl/13.4.7:
resolution: {integrity: sha512-wKRCQ27xCUJx5d6IivfjYGq8oVngqIhlhSAJntgXLt7Uo9sRT/3EppMHqUZRfyuNBTbykEre1s5166z+pvRB5A==} resolution: {integrity: sha512-T1kD2FWOEy5WPidOn1si0rYmWORNch4a/NR52Ghyp4q7KyxOCuiOfZzyhVC5tsLIBDH3+cNdB5DkD9afpNDaOw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
@@ -1442,8 +1442,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-linux-x64-gnu/13.4.2: /@next/swc-linux-x64-gnu/13.4.7:
resolution: {integrity: sha512-NpCa+UVhhuNeaFVUP1Bftm0uqtvLWq2JTm7+Ta48+2Uqj2mNXrDIvyn1DY/ZEfmW/1yvGBRaUAv9zkMkMRixQA==} resolution: {integrity: sha512-zaEC+iEiAHNdhl6fuwl0H0shnTzQoAoJiDYBUze8QTntE/GNPfTYpYboxF5LRYIjBwETUatvE0T64W6SKDipvg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@@ -1460,8 +1460,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-linux-x64-musl/13.4.2: /@next/swc-linux-x64-musl/13.4.7:
resolution: {integrity: sha512-ZWVC72x0lW4aj44e3khvBrj2oSYj1bD0jESmyah3zG/3DplEy/FOtYkMzbMjHTdDSheso7zH8GIlW6CDQnKhmQ==} resolution: {integrity: sha512-X6r12F8d8SKAtYJqLZBBMIwEqcTRvUdVm+xIq+l6pJqlgT2tNsLLf2i5Cl88xSsIytBICGsCNNHd+siD2fbWBA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
@@ -1478,8 +1478,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-win32-arm64-msvc/13.4.2: /@next/swc-win32-arm64-msvc/13.4.7:
resolution: {integrity: sha512-pLT+OWYpzJig5K4VKhLttlIfBcVZfr2+Xbjra0Tjs83NQSkFS+y7xx+YhCwvpEmXYLIvaggj2ONPyjbiigOvHQ==} resolution: {integrity: sha512-NPnmnV+vEIxnu6SUvjnuaWRglZzw4ox5n/MQTxeUhb5iwVWFedolPFebMNwgrWu4AELwvTdGtWjqof53AiWHcw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
@@ -1496,8 +1496,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-win32-ia32-msvc/13.4.2: /@next/swc-win32-ia32-msvc/13.4.7:
resolution: {integrity: sha512-dhpiksQCyGca4WY0fJyzK3FxMDFoqMb0Cn+uDB+9GYjpU2K5//UGPQlCwiK4JHxuhg8oLMag5Nf3/IPSJNG8jw==} resolution: {integrity: sha512-6Hxijm6/a8XqLQpOOf/XuwWRhcuc/g4rBB2oxjgCMuV9Xlr2bLs5+lXyh8w9YbAUMYR3iC9mgOlXbHa79elmXw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [ia32] cpu: [ia32]
os: [win32] os: [win32]
@@ -1514,8 +1514,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@next/swc-win32-x64-msvc/13.4.2: /@next/swc-win32-x64-msvc/13.4.7:
resolution: {integrity: sha512-O7bort1Vld00cu8g0jHZq3cbSTUNMohOEvYqsqE10+yfohhdPHzvzO+ziJRz4Dyyr/fYKREwS7gR4JC0soSOMw==} resolution: {integrity: sha512-sW9Yt36Db1nXJL+mTr2Wo0y+VkPWeYhygvcHj1FF0srVtV+VoDjxleKtny21QHaG05zdeZnw2fCtf2+dEqgwqA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@@ -3997,6 +3997,10 @@ packages:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
/glob-to-regexp/0.4.1:
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
dev: false
/glob/7.1.6: /glob/7.1.6:
resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
dependencies: dependencies:
@@ -5493,14 +5497,14 @@ packages:
/natural-compare/1.4.0: /natural-compare/1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
/next-themes/0.2.1_cmp7sjki5xcmfyvhcokzzink7a: /next-themes/0.2.1_5v7kwk6wz2hvmegftnptprfjvm:
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==} resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
peerDependencies: peerDependencies:
next: '*' next: '*'
react: '*' react: '*'
react-dom: '*' react-dom: '*'
dependencies: dependencies:
next: 13.4.2_bteaqif5pz4zkv4h4kccxuyuxu next: 13.4.7_bteaqif5pz4zkv4h4kccxuyuxu
react: 18.2.0 react: 18.2.0
react-dom: 18.2.0_react@18.2.0 react-dom: 18.2.0_react@18.2.0
dev: false dev: false
@@ -5552,14 +5556,13 @@ packages:
- babel-plugin-macros - babel-plugin-macros
dev: false dev: false
/next/13.4.2_bteaqif5pz4zkv4h4kccxuyuxu: /next/13.4.7_bteaqif5pz4zkv4h4kccxuyuxu:
resolution: {integrity: sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg==} resolution: {integrity: sha512-M8z3k9VmG51SRT6v5uDKdJXcAqLzP3C+vaKfLIAM0Mhx1um1G7MDnO63+m52qPdZfrTFzMZNzfsgvm3ghuVHIQ==}
engines: {node: '>=16.8.0'} engines: {node: '>=16.8.0'}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@opentelemetry/api': ^1.1.0 '@opentelemetry/api': ^1.1.0
fibers: '>= 3.1.0' fibers: '>= 3.1.0'
node-sass: ^6.0.0 || ^7.0.0
react: ^18.2.0 react: ^18.2.0
react-dom: ^18.2.0 react-dom: ^18.2.0
sass: ^1.3.0 sass: ^1.3.0
@@ -5568,12 +5571,10 @@ packages:
optional: true optional: true
fibers: fibers:
optional: true optional: true
node-sass:
optional: true
sass: sass:
optional: true optional: true
dependencies: dependencies:
'@next/env': 13.4.2 '@next/env': 13.4.7
'@swc/helpers': 0.5.1 '@swc/helpers': 0.5.1
busboy: 1.6.0 busboy: 1.6.0
caniuse-lite: 1.0.30001473 caniuse-lite: 1.0.30001473
@@ -5582,17 +5583,18 @@ packages:
react-dom: 18.2.0_react@18.2.0 react-dom: 18.2.0_react@18.2.0
sass: 1.62.0 sass: 1.62.0
styled-jsx: 5.1.1_cealaxz4az2u5bjp2e6aea3kui styled-jsx: 5.1.1_cealaxz4az2u5bjp2e6aea3kui
watchpack: 2.4.0
zod: 3.21.4 zod: 3.21.4
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 13.4.2 '@next/swc-darwin-arm64': 13.4.7
'@next/swc-darwin-x64': 13.4.2 '@next/swc-darwin-x64': 13.4.7
'@next/swc-linux-arm64-gnu': 13.4.2 '@next/swc-linux-arm64-gnu': 13.4.7
'@next/swc-linux-arm64-musl': 13.4.2 '@next/swc-linux-arm64-musl': 13.4.7
'@next/swc-linux-x64-gnu': 13.4.2 '@next/swc-linux-x64-gnu': 13.4.7
'@next/swc-linux-x64-musl': 13.4.2 '@next/swc-linux-x64-musl': 13.4.7
'@next/swc-win32-arm64-msvc': 13.4.2 '@next/swc-win32-arm64-msvc': 13.4.7
'@next/swc-win32-ia32-msvc': 13.4.2 '@next/swc-win32-ia32-msvc': 13.4.7
'@next/swc-win32-x64-msvc': 13.4.2 '@next/swc-win32-x64-msvc': 13.4.7
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
@@ -7549,6 +7551,14 @@ packages:
makeerror: 1.0.12 makeerror: 1.0.12
dev: true dev: true
/watchpack/2.4.0:
resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==}
engines: {node: '>=10.13.0'}
dependencies:
glob-to-regexp: 0.4.1
graceful-fs: 4.2.10
dev: false
/wcwidth/1.0.1: /wcwidth/1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies: dependencies: