From 98a116b2ee3279948f4a0078aa8551ddc87a5028 Mon Sep 17 00:00:00 2001 From: Deepjyoti Barman Date: Tue, 10 Dec 2024 18:47:58 +0530 Subject: [PATCH] Add init definition for handling registration and signup --- .../recipe/webauthn/recipeImplementation.ts | 41 ++++++++++++++++++- lib/ts/recipe/webauthn/types.ts | 1 + package-lock.json | 13 +++++- package.json | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index 4046bf3..5b0c08a 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -19,6 +19,7 @@ import { RecipeFunctionOptions, RecipeImplementationInput } from "../recipeModul import { PreAndPostAPIHookAction } from "./types"; import { GeneralErrorResponse, User } from "../../types"; import Multitenancy from "../multitenancy/recipe"; +import { RegistrationResponseJSON, startRegistration } from "@simplewebauthn/browser"; export default function getRecipeImplementation( recipeImplInput: RecipeImplementationInput @@ -353,11 +354,49 @@ export default function getRecipeImplementation( const registrationOptions = await this.registerOptions({ options, userContext, email }); if (registrationOptions?.status !== "OK") { // If we did not get an OK status, we need to return the error as is. + + // If the `status` is `RECOVER_ACCOUNT_TOKEN_INVALID_ERROR`, we need to throw an + // error since that should never happen as we are registering with an email + // and not a token. + if (registrationOptions?.status === "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR") { + throw new Error("Got `RECOVER_ACCOUNT_TOKEN_INVALID_ERROR` status that should never happen"); + } + return registrationOptions; } // We should have received a valid registration options response. - // TODO: Pass the registration options to simplewebauthn + let registrationResponse: RegistrationResponseJSON; + try { + registrationResponse = await startRegistration({ optionsJSON: registrationOptions }); + } catch (error: any) { + if (error.name === "InvalidStateError") { + return { status: "AUTHENTICATOR_ALREADY_REGISTERED" }; + } + + throw error; + } + + // We should have a valid registration response for the passed credentials + // and we are good to go ahead and verify them. + return await this.signUp({ + webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, + credential: { + id: registrationResponse.id, + rawId: registrationResponse.rawId, + response: { + clientDataJSON: registrationResponse.response.clientDataJSON, + attestationObject: registrationResponse.response.attestationObject, + transports: registrationResponse.response.transports, + userHandle: "TBD", // TODO: Fetch from the response + }, + authenticatorAttachment: registrationResponse.authenticatorAttachment || "platform", // TODO: Fix acc to what Victor suggests + type: registrationResponse.type, + clientExtensionResults: {}, // TODO: Fetch from the response. + }, + options, + userContext, + }); }, }; } diff --git a/lib/ts/recipe/webauthn/types.ts b/lib/ts/recipe/webauthn/types.ts index 390ab11..c7fb314 100644 --- a/lib/ts/recipe/webauthn/types.ts +++ b/lib/ts/recipe/webauthn/types.ts @@ -250,6 +250,7 @@ export type RecipeInterface = { | { status: "INVALID_GENERATED_OPTIONS_ERROR"; fetchResponse: Response } | { status: "INVALID_AUTHENTICATOR_ERROR"; reason: string; fetchResponse: Response } | { status: "EMAIL_ALREADY_EXISTS_ERROR"; fetchResponse: Response } + | { status: "AUTHENTICATOR_ALREADY_REGISTERED" } >; authenticateAndSignIn: (input: { email: string; options?: RecipeFunctionOptions; userContext: any }) => Promise< | { diff --git a/package-lock.json b/package-lock.json index 6d349d2..ab64ae1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,10 @@ "packages": { "": { "name": "supertokens-web-js", - "version": "0.14.0", + "version": "0.15.0", "license": "Apache-2.0", "dependencies": { + "@simplewebauthn/browser": "^13.0.0", "supertokens-js-override": "0.0.4", "supertokens-website": "^20.1.5" }, @@ -2218,6 +2219,11 @@ "node": ">= 8" } }, + "node_modules/@simplewebauthn/browser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.0.0.tgz", + "integrity": "sha512-7d/+gxoFoDQxq2EkLl/PuTIQ/rnSrA3bmr8L2Ij7bRyicJoCJX/NDGUNExyctB9nSDrEkkcrJMDkwpCYOGU3Lg==" + }, "node_modules/@size-limit/esbuild": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-8.2.6.tgz", @@ -12242,6 +12248,11 @@ "fastq": "^1.6.0" } }, + "@simplewebauthn/browser": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.0.0.tgz", + "integrity": "sha512-7d/+gxoFoDQxq2EkLl/PuTIQ/rnSrA3bmr8L2Ij7bRyicJoCJX/NDGUNExyctB9nSDrEkkcrJMDkwpCYOGU3Lg==" + }, "@size-limit/esbuild": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-8.2.6.tgz", diff --git a/package.json b/package.json index 0f7ff5e..bfbcebe 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "homepage": "https://github.com/supertokens/supertokens-web-js#readme", "dependencies": { + "@simplewebauthn/browser": "^13.0.0", "supertokens-js-override": "0.0.4", "supertokens-website": "^20.1.5" },