Skip to content

feat: Add MFA support for the WebAuthn recipe [v0.16.0] #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added support for auto inference of request/response body types along with query parameter types in querier methods.
- Adds a script to generate the types based on the FDI openapi spec.
- Include the `shouldTryLinkingToSessionUser` flag in the `Webauthn` recipe methods
- Update supported FDI versions and package version


## [0.15.0] - 2025-03-20

- Added `Webauthn` recipe to support logins using WebAuthN (Passkeys)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion bundle/emailpassword.0777370b1565b0ce79d6.js

This file was deleted.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/emailverification.9db2b314087603b5a7ce.js

This file was deleted.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/multifactorauth.5c1d9b591eda1a259829.js

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/multitenancy.b2eb625ac855c0f20933.js

This file was deleted.

1 change: 0 additions & 1 deletion bundle/oauth2provider.193a322e0969b7aad4eb.js

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/passwordless.c1f937cd504b61f83880.js

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/supertokens.681438d7dda2f4686c4d.js

This file was deleted.

1 change: 0 additions & 1 deletion bundle/thirdparty.1240cc4fa7b75fea6a4d.js

This file was deleted.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/totp.53dc276a6693f0c42c30.js

This file was deleted.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion bundle/website.41a7468e8fd759f30df0.js

This file was deleted.

1 change: 1 addition & 0 deletions bundle/website.c7860dc40a39421c659b.js

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion lib/build/recipe/webauthn/index.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions lib/build/recipe/webauthn/recipeImplementation.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion lib/build/recipe/webauthn/types.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion lib/ts/recipe/webauthn/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export default class RecipeWrapper {
static signUp(input: {
webauthnGeneratedOptionsId: string;
credential: RegistrationResponseJSON;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}): Promise<
Expand Down Expand Up @@ -197,6 +198,7 @@ export default class RecipeWrapper {
static signIn(input: {
webauthnGeneratedOptionsId: string;
credential: AuthenticationResponseJSON;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}): Promise<
Expand Down Expand Up @@ -376,6 +378,7 @@ export default class RecipeWrapper {
*/
static registerCredentialWithSignUp(input: {
email: string;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}): Promise<
Expand Down Expand Up @@ -427,7 +430,11 @@ export default class RecipeWrapper {
*
* @returns `{ status: "OK", ...}` if successful along a description of the user details (id, etc.) and email
*/
static authenticateCredentialWithSignIn(input: { options?: RecipeFunctionOptions; userContext: any }): Promise<
static authenticateCredentialWithSignIn(input: {
options?: RecipeFunctionOptions;
userContext: any;
shouldTryLinkingWithSessionUser?: boolean;
}): Promise<
| {
status: "OK";
user: User;
Expand Down
29 changes: 25 additions & 4 deletions lib/ts/recipe/webauthn/recipeImplementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ export default function getRecipeImplementation(
fetchResponse,
};
},
signUp: async function ({ webauthnGeneratedOptionsId, credential, options, userContext }) {
signUp: async function ({
webauthnGeneratedOptionsId,
credential,
options,
userContext,
shouldTryLinkingWithSessionUser,
}) {
const { jsonBody, fetchResponse } = await querier.post(
{
path: "/<tenantId>/webauthn/signup",
Expand All @@ -118,6 +124,7 @@ export default function getRecipeImplementation(
body: {
webauthnGeneratedOptionsId,
credential,
shouldTryLinkingWithSessionUser,
},
},
Querier.preparePreAPIHook({
Expand All @@ -138,7 +145,13 @@ export default function getRecipeImplementation(
fetchResponse,
};
},
signIn: async function ({ webauthnGeneratedOptionsId, credential, options, userContext }) {
signIn: async function ({
webauthnGeneratedOptionsId,
credential,
options,
userContext,
shouldTryLinkingWithSessionUser,
}) {
const { jsonBody, fetchResponse } = await querier.post(
{
path: "/<tenantId>/webauthn/signin",
Expand All @@ -153,6 +166,7 @@ export default function getRecipeImplementation(
body: {
webauthnGeneratedOptionsId,
credential,
shouldTryLinkingWithSessionUser,
},
},
Querier.preparePreAPIHook({
Expand Down Expand Up @@ -303,7 +317,12 @@ export default function getRecipeImplementation(
registrationResponse,
};
},
registerCredentialWithSignUp: async function ({ email, options, userContext }) {
registerCredentialWithSignUp: async function ({
email,
shouldTryLinkingWithSessionUser,
options,
userContext,
}) {
// Get the registration options by using the passed email ID.
const registrationOptions = await this.getRegisterOptions({ options, userContext, email });
if (registrationOptions?.status !== "OK") {
Expand All @@ -330,6 +349,7 @@ export default function getRecipeImplementation(
return await this.signUp({
webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId,
credential: registerCredentialResponse.registrationResponse,
shouldTryLinkingWithSessionUser,
options,
userContext,
});
Expand Down Expand Up @@ -357,7 +377,7 @@ export default function getRecipeImplementation(
authenticationResponse: authenticationResponse,
};
},
authenticateCredentialWithSignIn: async function ({ options, userContext }) {
authenticateCredentialWithSignIn: async function ({ shouldTryLinkingWithSessionUser, options, userContext }) {
// Make a call to get the sign in options using the entered email ID.
const signInOptions = await this.getSignInOptions({ options, userContext });
if (signInOptions?.status !== "OK") {
Expand All @@ -379,6 +399,7 @@ export default function getRecipeImplementation(
return await this.signIn({
webauthnGeneratedOptionsId: signInOptions.webauthnGeneratedOptionsId,
credential: authenticateCredentialResponse.authenticationResponse,
shouldTryLinkingWithSessionUser,
options: options,
userContext: userContext,
});
Expand Down
9 changes: 8 additions & 1 deletion lib/ts/recipe/webauthn/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ export type RecipeInterface = {
signUp: (input: {
webauthnGeneratedOptionsId: string;
credential: RegistrationResponseJSON;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}) => Promise<
Expand All @@ -175,6 +176,7 @@ export type RecipeInterface = {
signIn: (input: {
webauthnGeneratedOptionsId: string;
credential: AuthenticationResponseJSON;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}) => Promise<
Expand Down Expand Up @@ -256,6 +258,7 @@ export type RecipeInterface = {
>;
registerCredentialWithSignUp: (input: {
email: string;
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}) => Promise<
Expand Down Expand Up @@ -284,7 +287,11 @@ export type RecipeInterface = {
| { status: "FAILED_TO_REGISTER_USER"; error: any }
| { status: "WEBAUTHN_NOT_SUPPORTED"; error: any }
>;
authenticateCredentialWithSignIn: (input: { options?: RecipeFunctionOptions; userContext: any }) => Promise<
authenticateCredentialWithSignIn: (input: {
shouldTryLinkingWithSessionUser?: boolean;
options?: RecipeFunctionOptions;
userContext: any;
}) => Promise<
| {
status: "OK";
user: User;
Expand Down
Loading