From 47764a000a2758ed6b5c6629f30112b7a76c28bf Mon Sep 17 00:00:00 2001 From: Scott Trinh Date: Thu, 7 Mar 2024 16:08:01 -0500 Subject: [PATCH] Ensure WebAuthn redirect matches expected shape (#6987) In our framework helpers, we expect that the UI callback is either called with a `code` search parameter, or a `verification_email_sent_at` parameter, otherwise it treats the response as an error. --- .../auth_ext/_static/webauthn-authenticate.js | 29 ++++++++++++------- .../auth_ext/_static/webauthn-register.js | 18 +++++++----- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/edb/server/protocol/auth_ext/_static/webauthn-authenticate.js b/edb/server/protocol/auth_ext/_static/webauthn-authenticate.js index 787afcd385..c4bdb61ff9 100644 --- a/edb/server/protocol/auth_ext/_static/webauthn-authenticate.js +++ b/edb/server/protocol/auth_ext/_static/webauthn-authenticate.js @@ -30,20 +30,32 @@ async function onAuthenticateSubmit(form) { const redirectOnFailure = formData.get("redirect_on_failure"); const redirectTo = formData.get("redirect_to"); - if (redirectTo === null) { - throw new Error("Missing redirect_to parameter"); + const missingFields = Object.entries({ + email, + challenge, + redirectTo, + }).filter(([k, v]) => !v); + if (missingFields.length > 0) { + throw new Error( + "Missing required parameters: " + missingFields.map(([k]) => k).join(", ") + ); } try { - const maybeCode = await authenticate({ + const response = await authenticate({ email, provider, challenge, }); const redirectUrl = new URL(redirectTo); - if (maybeCode !== null) { - redirectUrl.searchParams.append("code", maybeCode); + if ("code" in response) { + redirectUrl.searchParams.append("code", response.code); + } else if ("verification_email_sent_at" in response) { + redirectUrl.searchParams.append( + "verification_email_sent_at", + response.verification_email_sent_at + ); } window.location.href = redirectUrl.href; @@ -72,8 +84,7 @@ const WEBAUTHN_AUTHENTICATE_URL = new URL( * @param {string} props.email - Email address to register * @param {string} props.provider - WebAuthn provider * @param {string} props.challenge - PKCE challenge - * @returns {Promise} - The PKCE code or null if the application - * requires email verification + * @returns {Promise} - The server response */ export async function authenticate({ email, provider, challenge }) { // Check if WebAuthn is supported @@ -98,13 +109,11 @@ export async function authenticate({ email, provider, challenge }) { }); // Register the credentials on the server - const registerResult = await authenticateAssertion({ + return await authenticateAssertion({ email, assertion, challenge, }); - - return registerResult.code ?? null; } /** diff --git a/edb/server/protocol/auth_ext/_static/webauthn-register.js b/edb/server/protocol/auth_ext/_static/webauthn-register.js index 72c4fbcda6..f3d8b67a5e 100644 --- a/edb/server/protocol/auth_ext/_static/webauthn-register.js +++ b/edb/server/protocol/auth_ext/_static/webauthn-register.js @@ -45,7 +45,7 @@ export async function onRegisterSubmit(form) { ); } - const maybeCode = await register({ + const response = await register({ email, provider, challenge, @@ -54,8 +54,13 @@ export async function onRegisterSubmit(form) { const redirectUrl = new URL(redirectTo); redirectUrl.searchParams.append("isSignUp", "true"); - if (maybeCode !== null) { - redirectUrl.searchParams.append("code", maybeCode); + if ("code" in response) { + redirectUrl.searchParams.append("code", response.code); + } else if ("verification_email_sent_at" in response) { + redirectUrl.searchParams.append( + "verification_email_sent_at", + response.verification_email_sent_at + ); } window.location.href = redirectUrl.href; @@ -83,8 +88,7 @@ const WEBAUTHN_REGISTER_URL = new URL("../webauthn/register", window.location); * @param {string} props.provider - WebAuthn provider * @param {string} props.challenge - PKCE challenge * @param {string} props.verifyUrl - URL to verify email after registration - * @returns {Promise} - The PKCE code or null if the application - * requires email verification + * @returns {Promise} - The server response */ export async function register({ email, provider, challenge, verifyUrl }) { // Check if WebAuthn is supported @@ -109,15 +113,13 @@ export async function register({ email, provider, challenge, verifyUrl }) { }); // Register the credentials on the server - const registerResult = await registerCredentials({ + return await registerCredentials({ email, credentials, provider, challenge, verifyUrl, }); - - return registerResult.code ?? null; } /**