mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-12 05:12:20 +00:00
fix webauthn flow, state
This commit is contained in:
@@ -13,7 +13,7 @@ export default async function Page({
|
||||
}: {
|
||||
searchParams: Record<string | number | symbol, string | undefined>;
|
||||
}) {
|
||||
const { loginName, altPassword } = searchParams;
|
||||
const { loginName, altPassword, authRequestId } = searchParams;
|
||||
|
||||
const sessionFactors = await loadSession(loginName);
|
||||
|
||||
@@ -48,6 +48,7 @@ export default async function Page({
|
||||
{loginName && (
|
||||
<LoginPasskey
|
||||
loginName={loginName}
|
||||
authRequestId={authRequestId}
|
||||
altPassword={altPassword === "true"}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -9,7 +9,7 @@ export default async function Page({
|
||||
}: {
|
||||
searchParams: Record<string | number | symbol, string | undefined>;
|
||||
}) {
|
||||
const { loginName, promptPasswordless, alt } = searchParams;
|
||||
const { loginName, promptPasswordless, authRequestId, alt } = searchParams;
|
||||
const sessionFactors = await loadSession(loginName);
|
||||
|
||||
async function loadSession(loginName?: string) {
|
||||
@@ -46,6 +46,7 @@ export default async function Page({
|
||||
|
||||
<PasswordForm
|
||||
loginName={loginName}
|
||||
authRequestId={authRequestId}
|
||||
promptPasswordless={promptPasswordless === "true"}
|
||||
isAlternative={alt === "true"}
|
||||
/>
|
||||
|
||||
@@ -45,12 +45,11 @@ export async function POST(request: NextRequest) {
|
||||
if (body) {
|
||||
const { loginName, authRequestId } = body;
|
||||
|
||||
const domain: string = request.nextUrl.hostname;
|
||||
// const domain: string = request.nextUrl.hostname;
|
||||
|
||||
return createSessionAndUpdateCookie(
|
||||
loginName,
|
||||
undefined,
|
||||
domain,
|
||||
undefined,
|
||||
authRequestId
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ export async function POST(request: NextRequest) {
|
||||
return createSessionAndUpdateCookie(
|
||||
loginName,
|
||||
password,
|
||||
domain,
|
||||
undefined,
|
||||
undefined
|
||||
).then((session) => {
|
||||
return NextResponse.json(session);
|
||||
@@ -44,7 +44,7 @@ export async function PUT(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
|
||||
if (body) {
|
||||
const { loginName, password, challenges, passkey } = body;
|
||||
const { loginName, password, challenges, passkey, authRequestId } = body;
|
||||
|
||||
const recentPromise: Promise<SessionCookie> = loginName
|
||||
? getSessionCookieByLoginName(loginName).catch((error) => {
|
||||
@@ -54,7 +54,7 @@ export async function PUT(request: NextRequest) {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
const domain: string = request.nextUrl.hostname;
|
||||
// const domain: string = request.nextUrl.hostname;
|
||||
|
||||
return recentPromise
|
||||
.then((recent) => {
|
||||
@@ -64,8 +64,8 @@ export async function PUT(request: NextRequest) {
|
||||
recent.loginName,
|
||||
password,
|
||||
passkey,
|
||||
domain,
|
||||
challenges
|
||||
challenges,
|
||||
authRequestId
|
||||
).then((session) => {
|
||||
return NextResponse.json({
|
||||
sessionId: session.id,
|
||||
|
||||
@@ -101,7 +101,7 @@ export async function createSession(
|
||||
server: ZitadelServer,
|
||||
loginName: string,
|
||||
password: string | undefined,
|
||||
challenges: RequestChallenges
|
||||
challenges: RequestChallenges | undefined
|
||||
): Promise<CreateSessionResponse | undefined> {
|
||||
const sessionService = session.getSession(server);
|
||||
return password
|
||||
@@ -125,7 +125,7 @@ export async function setSession(
|
||||
sessionToken: string,
|
||||
password: string | undefined,
|
||||
webAuthN: { credentialAssertionData: any } | undefined,
|
||||
challenges: RequestChallenges
|
||||
challenges: RequestChallenges | undefined
|
||||
): Promise<SetSessionResponse | undefined> {
|
||||
const sessionService = session.getSession(server);
|
||||
|
||||
|
||||
@@ -9,10 +9,15 @@ import { Spinner } from "./Spinner";
|
||||
|
||||
type Props = {
|
||||
loginName: string;
|
||||
authRequestId?: string;
|
||||
altPassword: boolean;
|
||||
};
|
||||
|
||||
export default function LoginPasskey({ loginName, altPassword }: Props) {
|
||||
export default function LoginPasskey({
|
||||
loginName,
|
||||
authRequestId,
|
||||
altPassword,
|
||||
}: Props) {
|
||||
const [error, setError] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
@@ -60,6 +65,7 @@ export default function LoginPasskey({ loginName, altPassword }: Props) {
|
||||
body: JSON.stringify({
|
||||
loginName,
|
||||
challenges: [1], // request passkey challenge
|
||||
authRequestId,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -81,6 +87,7 @@ export default function LoginPasskey({ loginName, altPassword }: Props) {
|
||||
body: JSON.stringify({
|
||||
loginName,
|
||||
passkey: data,
|
||||
authRequestId,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -168,11 +175,16 @@ export default function LoginPasskey({ loginName, altPassword }: Props) {
|
||||
<Button
|
||||
type="button"
|
||||
variant={ButtonVariants.Secondary}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
"/password?" + new URLSearchParams({ loginName, alt: "true" }) // alt is set because password is requested as alternative auth method, so passwordless prompt can be escaped
|
||||
)
|
||||
}
|
||||
onClick={() => {
|
||||
const params = { loginName, alt: "true" };
|
||||
|
||||
return router.push(
|
||||
"/password?" +
|
||||
new URLSearchParams(
|
||||
authRequestId ? { ...params, authRequestId } : params
|
||||
) // alt is set because password is requested as alternative auth method, so passwordless prompt can be escaped
|
||||
);
|
||||
}}
|
||||
>
|
||||
use password
|
||||
</Button>
|
||||
|
||||
@@ -14,12 +14,14 @@ type Inputs = {
|
||||
|
||||
type Props = {
|
||||
loginName?: string;
|
||||
authRequestId?: string;
|
||||
isAlternative?: boolean; // whether password was requested as alternative auth method
|
||||
promptPasswordless?: boolean;
|
||||
};
|
||||
|
||||
export default function PasswordForm({
|
||||
loginName,
|
||||
authRequestId,
|
||||
promptPasswordless,
|
||||
isAlternative,
|
||||
}: Props) {
|
||||
@@ -44,6 +46,7 @@ export default function PasswordForm({
|
||||
body: JSON.stringify({
|
||||
loginName,
|
||||
password: values.password,
|
||||
authRequestId,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ export default function RegisterFormWithoutPassword({ legal }: Props) {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
loginName: loginName,
|
||||
// authRequestId, register does not need an oidc callback at the end
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ export default function SessionItem({
|
||||
}
|
||||
|
||||
const validPassword = session?.factors?.password?.verifiedAt;
|
||||
const validPasskey = session?.factors?.passkey?.verifiedAt;
|
||||
const validPasskey = session?.factors?.webAuthN?.verifiedAt;
|
||||
|
||||
const validUser = validPassword || validPasskey;
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ export default function SetPasswordForm({
|
||||
body: JSON.stringify({
|
||||
loginName: loginName,
|
||||
password: password,
|
||||
// authRequestId, register does not need an oidc callback
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -65,16 +65,18 @@ export default function UsernameForm({
|
||||
const method = response.authMethodTypes[0];
|
||||
switch (method) {
|
||||
case 1: //AuthenticationMethodType.AUTHENTICATION_METHOD_TYPE_PASSWORD:
|
||||
const paramsPassword: any = { loginName: values.loginName };
|
||||
|
||||
if (loginSettings?.passkeysType === 1) {
|
||||
paramsPassword.promptPasswordless = `true`; // PasskeysType.PASSKEYS_TYPE_ALLOWED,
|
||||
}
|
||||
|
||||
if (authRequestId) {
|
||||
paramsPassword.authRequestId = authRequestId;
|
||||
}
|
||||
|
||||
return router.push(
|
||||
"/password?" +
|
||||
new URLSearchParams(
|
||||
loginSettings?.passkeysType === 1
|
||||
? {
|
||||
loginName: values.loginName,
|
||||
promptPasswordless: `true`, // PasskeysType.PASSKEYS_TYPE_ALLOWED,
|
||||
}
|
||||
: { loginName: values.loginName }
|
||||
)
|
||||
"/password?" + new URLSearchParams(paramsPassword)
|
||||
);
|
||||
case 2: // AuthenticationMethodType.AUTHENTICATION_METHOD_TYPE_PASSKEY
|
||||
return router.push(
|
||||
@@ -82,16 +84,17 @@ export default function UsernameForm({
|
||||
new URLSearchParams({ loginName: values.loginName })
|
||||
);
|
||||
default:
|
||||
const paramsPasskey: any = { loginName: values.loginName };
|
||||
|
||||
if (loginSettings?.passkeysType === 1) {
|
||||
paramsPasskey.promptPasswordless = `true`; // PasskeysType.PASSKEYS_TYPE_ALLOWED,
|
||||
}
|
||||
|
||||
if (authRequestId) {
|
||||
paramsPasskey.authRequestId = authRequestId;
|
||||
}
|
||||
return router.push(
|
||||
"/password?" +
|
||||
new URLSearchParams(
|
||||
loginSettings?.passkeysType === 1
|
||||
? {
|
||||
loginName: values.loginName,
|
||||
promptPasswordless: `true`, // PasskeysType.PASSKEYS_TYPE_ALLOWED,
|
||||
}
|
||||
: { loginName: values.loginName }
|
||||
)
|
||||
"/password?" + new URLSearchParams(paramsPasskey)
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
|
||||
@@ -4,19 +4,17 @@ import {
|
||||
addSessionToCookie,
|
||||
updateSessionCookie,
|
||||
} from "./cookies";
|
||||
import { ChallengeKind, Session, Challenges } from "@zitadel/server";
|
||||
import { Session, Challenges, RequestChallenges } from "@zitadel/server";
|
||||
|
||||
export async function createSessionAndUpdateCookie(
|
||||
loginName: string,
|
||||
password: string | undefined,
|
||||
domain: string,
|
||||
challenges: ChallengeKind[] | undefined,
|
||||
challenges: RequestChallenges | undefined,
|
||||
authRequestId: string | undefined
|
||||
): Promise<Session> {
|
||||
const createdSession = await createSession(
|
||||
server,
|
||||
loginName,
|
||||
domain,
|
||||
password,
|
||||
challenges
|
||||
);
|
||||
@@ -61,15 +59,13 @@ export async function setSessionAndUpdateCookie(
|
||||
loginName: string,
|
||||
password: string | undefined,
|
||||
passkey: { credentialAssertionData: any } | undefined,
|
||||
domain: string | undefined,
|
||||
challenges: ChallengeKind[] | undefined,
|
||||
challenges: RequestChallenges | undefined,
|
||||
authRequestId: string | undefined
|
||||
): Promise<SessionWithChallenges> {
|
||||
return setSession(
|
||||
server,
|
||||
sessionId,
|
||||
sessionToken,
|
||||
domain,
|
||||
password,
|
||||
passkey,
|
||||
challenges
|
||||
|
||||
Reference in New Issue
Block a user