diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index 5b0c08a..0556e63 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -19,7 +19,12 @@ 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"; +import { + AuthenticationResponseJSON, + RegistrationResponseJSON, + startAuthentication, + startRegistration, +} from "@simplewebauthn/browser"; export default function getRecipeImplementation( recipeImplInput: RecipeImplementationInput @@ -381,23 +386,37 @@ export default function getRecipeImplementation( // 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. - }, + credential: registrationResponse, options, userContext, }); }, + authenticateAndSignIn: async function ({ email, options, userContext }) { + // Make a call to get the sign in options using the entered email ID. + const signInOptions = await this.signInOptions({ email, options, userContext }); + if (signInOptions?.status !== "OK") { + // We want to return the error as is if status was not "OK" + return signInOptions; + } + + // We should have the options ready and are good to start the authentication + let authenticationResponse: AuthenticationResponseJSON; + try { + authenticationResponse = await startAuthentication({ optionsJSON: signInOptions }); + } catch (error: any) { + // TODO: Do we need to do something with the error besides throwing it? + throw error; + } + + // We should have a valid authentication response at this point so we can + // go ahead and sign in the user. + return await this.signIn({ + webauthnGeneratedOptionsId: signInOptions.webauthnGeneratedOptionsId, + credential: authenticationResponse, + options: options, + userContext: userContext, + }); + }, }; } diff --git a/lib/ts/recipe/webauthn/types.ts b/lib/ts/recipe/webauthn/types.ts index c7fb314..6d11f3d 100644 --- a/lib/ts/recipe/webauthn/types.ts +++ b/lib/ts/recipe/webauthn/types.ts @@ -13,6 +13,7 @@ * under the License. */ +import { AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/browser"; import { GeneralErrorResponse, User } from "../../types"; import { NormalisedInputType as AuthRecipeNormalisedInputType, @@ -71,7 +72,7 @@ export type CredentialPayload = { userHandle: string; }; authenticatorAttachment: "platform" | "cross-platform"; - clientExtensionResults: Record; + clientExtensionResults: any; type: "public-key"; }; @@ -144,7 +145,7 @@ export type RecipeInterface = { >; signUp: (input: { webauthnGeneratedOptionsId: string; - credential: CredentialPayload; + credential: RegistrationResponseJSON; options?: RecipeFunctionOptions; userContext: any; }) => Promise< @@ -167,7 +168,7 @@ export type RecipeInterface = { >; signIn: (input: { webauthnGeneratedOptionsId: string; - credential: CredentialPayload; + credential: AuthenticationResponseJSON; options?: RecipeFunctionOptions; userContext: any; }) => Promise<