Skip to content
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.50] - 2025-08-11

- Add WebAuthn credential management methods: `listCredentials`, `removeCredential`
- Added `createAndRegisterCredentialWithUser` method that creates and registers a credential with a user

### Breaking changes

- The `registerCredential` method has been renamed to `createCredential`. This was done to better represent the creation of a credential and not the actual registration of it with the backend API. The new `registerCredential` implementation now calls the backend API.

## [0.49.1] - 2025-03-27

- Fixed a type issue making the WebauthnPreBuitlUI not produce a type error when added to the prebuiltUIList
Expand Down
108 changes: 105 additions & 3 deletions lib/build/recipe/webauthn/index.d.ts

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

5 changes: 4 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.

26 changes: 23 additions & 3 deletions lib/build/webauthn.js

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

2 changes: 1 addition & 1 deletion lib/build/webauthnprebuiltui.js

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

Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const RecoverAccountUsingToken: React.FC<RecoverAccountWithTokenProps> =

// Use the register options to register the credential and recover the account.
// We should have received a valid registration options response.
const registerCredentialResponse = await props.recipe.webJSRecipe.registerCredential({
const registerCredentialResponse = await props.recipe.webJSRecipe.createCredential({
registrationOptions: registerOptions,
userContext: props.userContext,
});
Expand Down
79 changes: 75 additions & 4 deletions lib/ts/recipe/webauthn/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ export default class Wrapper {
return Webauthn.getInstanceOrThrow().webJSRecipe.recoverAccount(input);
}

static registerCredential(input: {
static createCredential(input: {
registrationOptions: Omit<RegistrationOptions, "fetchResponse" | "status">;
userContext: any;
}): Promise<
Expand All @@ -267,7 +267,7 @@ export default class Wrapper {
error: any;
}
> {
return Webauthn.getInstanceOrThrow().webJSRecipe.registerCredential(input);
return Webauthn.getInstanceOrThrow().webJSRecipe.createCredential(input);
}

static authenticateCredential(input: {
Expand Down Expand Up @@ -439,6 +439,69 @@ export default class Wrapper {
return Webauthn.getInstanceOrThrow().webJSRecipe.registerCredentialWithRecoverAccount(input);
}

static listCredentials(input: { options?: RecipeFunctionOptions; userContext: any }): Promise<
| {
status: "OK";
credentials: {
webauthnCredentialId: string;
relyingPartyId: string;
recipeUserId: string;
createdAt: number;
}[];
}
| GeneralErrorResponse
> {
return Webauthn.getInstanceOrThrow().webJSRecipe.listCredentials(input);
}

static removeCredential(input: {
webauthnCredentialId: string;
userContext: any;
}): Promise<
{ status: "OK" } | GeneralErrorResponse | { status: "CREDENTIAL_NOT_FOUND_ERROR"; fetchResponse: Response }
> {
return Webauthn.getInstanceOrThrow().webJSRecipe.removeCredential(input);
}

static createAndRegisterCredentialForSessionUser(input: {
recipeUserId: string;
email: string;
options?: RecipeFunctionOptions;
userContext: any;
}): Promise<
| { status: "OK" }
| GeneralErrorResponse
| { status: "REGISTER_CREDENTIAL_NOT_ALLOWED"; reason?: string }
| { status: "INVALID_EMAIL_ERROR"; err: string }
| { status: "INVALID_CREDENTIALS_ERROR" }
| { status: "OPTIONS_NOT_FOUND_ERROR" }
| { status: "INVALID_OPTIONS_ERROR" }
| { status: "INVALID_AUTHENTICATOR_ERROR"; reason?: string }
| { status: "AUTHENTICATOR_ALREADY_REGISTERED" }
| { status: "FAILED_TO_REGISTER_USER"; error: any }
| { status: "WEBAUTHN_NOT_SUPPORTED"; error: any }
> {
return Webauthn.getInstanceOrThrow().webJSRecipe.createAndRegisterCredentialForSessionUser(input);
}

static registerCredential(input: {
recipeUserId: string;
webauthnGeneratedOptionsId: string;
credential: RegistrationResponseJSON;
options?: RecipeFunctionOptions;
userContext: any;
}): Promise<
| { status: "OK" }
| GeneralErrorResponse
| { status: "REGISTER_CREDENTIAL_NOT_ALLOWED"; reason?: string }
| { status: "INVALID_CREDENTIALS_ERROR" }
| { status: "OPTIONS_NOT_FOUND_ERROR" }
| { status: "INVALID_OPTIONS_ERROR" }
| { status: "INVALID_AUTHENTICATOR_ERROR"; reason?: string }
> {
return Webauthn.getInstanceOrThrow().webJSRecipe.registerCredential(input);
}

static doesBrowserSupportWebAuthn(input: { userContext: any }): Promise<
| {
status: "OK";
Expand All @@ -464,11 +527,15 @@ const signIn = Wrapper.signIn;
const getEmailExists = Wrapper.getEmailExists;
const generateRecoverAccountToken = Wrapper.generateRecoverAccountToken;
const recoverAccount = Wrapper.recoverAccount;
const registerCredential = Wrapper.registerCredential;
const createCredential = Wrapper.createCredential;
const authenticateCredential = Wrapper.authenticateCredential;
const registerCredentialWithSignUp = Wrapper.registerCredentialWithSignUp;
const authenticateCredentialWithSignIn = Wrapper.authenticateCredentialWithSignIn;
const registerCredentialWithRecoverAccount = Wrapper.registerCredentialWithRecoverAccount;
const createAndRegisterCredentialForSessionUser = Wrapper.createAndRegisterCredentialForSessionUser;
const listCredentials = Wrapper.listCredentials;
const removeCredential = Wrapper.removeCredential;
const registerCredential = Wrapper.registerCredential;
const doesBrowserSupportWebAuthn = Wrapper.doesBrowserSupportWebAuthn;
const WebauthnComponentsOverrideProvider = Wrapper.ComponentsOverrideProvider;

Expand All @@ -481,11 +548,15 @@ export {
getEmailExists,
generateRecoverAccountToken,
recoverAccount,
registerCredential,
createCredential,
authenticateCredential,
registerCredentialWithSignUp,
authenticateCredentialWithSignIn,
registerCredentialWithRecoverAccount,
createAndRegisterCredentialForSessionUser,
doesBrowserSupportWebAuthn,
WebauthnComponentsOverrideProvider,
listCredentials,
removeCredential,
registerCredential,
};
5 changes: 4 additions & 1 deletion lib/ts/recipe/webauthn/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ export type PreAndPostAPIHookAction =
| "SIGN_IN"
| "EMAIL_EXISTS"
| "GENERATE_RECOVER_ACCOUNT_TOKEN"
| "RECOVER_ACCOUNT";
| "RECOVER_ACCOUNT"
| "REGISTER_CREDENTIAL"
| "REMOVE_CREDENTIAL"
| "LIST_CREDENTIALS";

export type OnHandleEventContext =
| {
Expand Down
Loading
Loading