diff --git a/CHANGELOG.md b/CHANGELOG.md index c7a16c9a..8a21783e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 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 +- Add WebAuthn list and remove credential methods +- Added `createAndRegisterCredentialForSessionUser` 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.15.0] - 2025-03-20 diff --git a/lib/build/querier.d.ts b/lib/build/querier.d.ts index 2dc52eef..a7fdea2c 100644 --- a/lib/build/querier.d.ts +++ b/lib/build/querier.d.ts @@ -25,6 +25,36 @@ export default class Querier { private safelyStringifyBody; get: < P extends + | "/mfa/info" + | "/totp/device/list" + | "/totp/device" + | "/totp/device/remove" + | "/totp/device/verify" + | "/totp/verify" + | "//signinup/code" + | "//signinup/code/resend" + | "//signinup/code/consume" + | "//signup/email/exists⠀⠀" + | "//passwordless/email/exists" + | "//signup/phoneNumber/exists" + | "//passwordless/phonenumber/exists" + | "/signout" + | "/session/refresh" + | "//signin" + | "//signup" + | "//signup/email/exists" + | "//emailpassword/email/exists" + | "//user/password/reset/token" + | "//user/password/reset" + | "//signinup" + | "//authorisationurl" + | "//loginmethods" + | "/callback/apple" + | "/user/email/verify/token" + | "//user/email/verify" + | "/user/email/verify" + | "/jwt/jwks.json" + | "/.well-known/openid-configuration" | "/oauth/login" | "/oauth/auth" | "/oauth/token" @@ -34,6 +64,7 @@ export default class Querier { | "/oauth/end_session" | "/oauth/login/info" | "/oauth/logout" + | "/example" | "//webauthn/options/register" | "//webauthn/options/signin" | "//webauthn/signup" @@ -41,10 +72,11 @@ export default class Querier { | "//webauthn/recover/account/token" | "//webauthn/recover/account" | "//webauthn/credential" + | "//webauthn/credential/remove" + | "//webauthn/credential/list" | "//webauthn/email/exists" | "//user/webauthn/reset/token" | "//user/webauthn/reset" - | keyof import("./sdk/versions/3.1/schema").paths >( template: PathParam, config: RequestInitWithInferredBody, @@ -64,6 +96,36 @@ export default class Querier { }>; post: < P extends + | "/mfa/info" + | "/totp/device/list" + | "/totp/device" + | "/totp/device/remove" + | "/totp/device/verify" + | "/totp/verify" + | "//signinup/code" + | "//signinup/code/resend" + | "//signinup/code/consume" + | "//signup/email/exists⠀⠀" + | "//passwordless/email/exists" + | "//signup/phoneNumber/exists" + | "//passwordless/phonenumber/exists" + | "/signout" + | "/session/refresh" + | "//signin" + | "//signup" + | "//signup/email/exists" + | "//emailpassword/email/exists" + | "//user/password/reset/token" + | "//user/password/reset" + | "//signinup" + | "//authorisationurl" + | "//loginmethods" + | "/callback/apple" + | "/user/email/verify/token" + | "//user/email/verify" + | "/user/email/verify" + | "/jwt/jwks.json" + | "/.well-known/openid-configuration" | "/oauth/login" | "/oauth/auth" | "/oauth/token" @@ -73,6 +135,7 @@ export default class Querier { | "/oauth/end_session" | "/oauth/login/info" | "/oauth/logout" + | "/example" | "//webauthn/options/register" | "//webauthn/options/signin" | "//webauthn/signup" @@ -80,10 +143,11 @@ export default class Querier { | "//webauthn/recover/account/token" | "//webauthn/recover/account" | "//webauthn/credential" + | "//webauthn/credential/remove" + | "//webauthn/credential/list" | "//webauthn/email/exists" | "//user/webauthn/reset/token" | "//user/webauthn/reset" - | keyof import("./sdk/versions/3.1/schema").paths >( template: PathParam, config: RequestInitWithInferredBody, @@ -103,6 +167,36 @@ export default class Querier { }>; delete: < P extends + | "/mfa/info" + | "/totp/device/list" + | "/totp/device" + | "/totp/device/remove" + | "/totp/device/verify" + | "/totp/verify" + | "//signinup/code" + | "//signinup/code/resend" + | "//signinup/code/consume" + | "//signup/email/exists⠀⠀" + | "//passwordless/email/exists" + | "//signup/phoneNumber/exists" + | "//passwordless/phonenumber/exists" + | "/signout" + | "/session/refresh" + | "//signin" + | "//signup" + | "//signup/email/exists" + | "//emailpassword/email/exists" + | "//user/password/reset/token" + | "//user/password/reset" + | "//signinup" + | "//authorisationurl" + | "//loginmethods" + | "/callback/apple" + | "/user/email/verify/token" + | "//user/email/verify" + | "/user/email/verify" + | "/jwt/jwks.json" + | "/.well-known/openid-configuration" | "/oauth/login" | "/oauth/auth" | "/oauth/token" @@ -112,6 +206,7 @@ export default class Querier { | "/oauth/end_session" | "/oauth/login/info" | "/oauth/logout" + | "/example" | "//webauthn/options/register" | "//webauthn/options/signin" | "//webauthn/signup" @@ -119,10 +214,11 @@ export default class Querier { | "//webauthn/recover/account/token" | "//webauthn/recover/account" | "//webauthn/credential" + | "//webauthn/credential/remove" + | "//webauthn/credential/list" | "//webauthn/email/exists" | "//user/webauthn/reset/token" | "//user/webauthn/reset" - | keyof import("./sdk/versions/3.1/schema").paths >( template: PathParam, config: RequestInitWithInferredBody, @@ -144,6 +240,36 @@ export default class Querier { }>; put: < P extends + | "/mfa/info" + | "/totp/device/list" + | "/totp/device" + | "/totp/device/remove" + | "/totp/device/verify" + | "/totp/verify" + | "//signinup/code" + | "//signinup/code/resend" + | "//signinup/code/consume" + | "//signup/email/exists⠀⠀" + | "//passwordless/email/exists" + | "//signup/phoneNumber/exists" + | "//passwordless/phonenumber/exists" + | "/signout" + | "/session/refresh" + | "//signin" + | "//signup" + | "//signup/email/exists" + | "//emailpassword/email/exists" + | "//user/password/reset/token" + | "//user/password/reset" + | "//signinup" + | "//authorisationurl" + | "//loginmethods" + | "/callback/apple" + | "/user/email/verify/token" + | "//user/email/verify" + | "/user/email/verify" + | "/jwt/jwks.json" + | "/.well-known/openid-configuration" | "/oauth/login" | "/oauth/auth" | "/oauth/token" @@ -153,6 +279,7 @@ export default class Querier { | "/oauth/end_session" | "/oauth/login/info" | "/oauth/logout" + | "/example" | "//webauthn/options/register" | "//webauthn/options/signin" | "//webauthn/signup" @@ -160,10 +287,11 @@ export default class Querier { | "//webauthn/recover/account/token" | "//webauthn/recover/account" | "//webauthn/credential" + | "//webauthn/credential/remove" + | "//webauthn/credential/list" | "//webauthn/email/exists" | "//user/webauthn/reset/token" | "//user/webauthn/reset" - | keyof import("./sdk/versions/3.1/schema").paths >( template: PathParam, config: RequestInitWithInferredBody, @@ -193,6 +321,36 @@ export default class Querier { }>; getFullUrl: < P extends + | "/mfa/info" + | "/totp/device/list" + | "/totp/device" + | "/totp/device/remove" + | "/totp/device/verify" + | "/totp/verify" + | "//signinup/code" + | "//signinup/code/resend" + | "//signinup/code/consume" + | "//signup/email/exists⠀⠀" + | "//passwordless/email/exists" + | "//signup/phoneNumber/exists" + | "//passwordless/phonenumber/exists" + | "/signout" + | "/session/refresh" + | "//signin" + | "//signup" + | "//signup/email/exists" + | "//emailpassword/email/exists" + | "//user/password/reset/token" + | "//user/password/reset" + | "//signinup" + | "//authorisationurl" + | "//loginmethods" + | "/callback/apple" + | "/user/email/verify/token" + | "//user/email/verify" + | "/user/email/verify" + | "/jwt/jwks.json" + | "/.well-known/openid-configuration" | "/oauth/login" | "/oauth/auth" | "/oauth/token" @@ -202,6 +360,7 @@ export default class Querier { | "/oauth/end_session" | "/oauth/login/info" | "/oauth/logout" + | "/example" | "//webauthn/options/register" | "//webauthn/options/signin" | "//webauthn/signup" @@ -209,10 +368,11 @@ export default class Querier { | "//webauthn/recover/account/token" | "//webauthn/recover/account" | "//webauthn/credential" + | "//webauthn/credential/remove" + | "//webauthn/credential/list" | "//webauthn/email/exists" | "//user/webauthn/reset/token" - | "//user/webauthn/reset" - | keyof import("./sdk/versions/3.1/schema").paths, + | "//user/webauthn/reset", M extends Method >( path: PathParam diff --git a/lib/build/recipe/webauthn/index.d.ts b/lib/build/recipe/webauthn/index.d.ts index 22ea5b91..4df95d78 100644 --- a/lib/build/recipe/webauthn/index.d.ts +++ b/lib/build/recipe/webauthn/index.d.ts @@ -302,7 +302,7 @@ export default class RecipeWrapper { } >; /** - * Register credential with the passed options by using native webauthn functions. + * Creates the credential with the passed options by using native webauthn functions. * * It uses `@simplewebauthn/browser` to make the webauthn calls. * @@ -310,7 +310,7 @@ export default class RecipeWrapper { * * @returns `{ status: "OK", ...}` if successful along with registration response received */ - static registerCredential(input: { + static createCredential(input: { registrationOptions: Omit; userContext: any; }): Promise< @@ -540,6 +540,151 @@ export default class RecipeWrapper { error: any; } >; + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param email Email of the WebAuthn user to register the credential for + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation} + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static createAndRegisterCredentialForSessionUser(input: { + email: string; + recipeUserId: string; + options?: RecipeFunctionOptions; + userContext: any; + }): Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | 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; + } + >; + /** + * List the credentials for the user + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful along with a list of the user's credentials + */ + static listCredentials(input: { options?: RecipeFunctionOptions; userContext: any }): Promise< + | { + status: "OK"; + credentials: { + webauthnCredentialId: string; + relyingPartyId: string; + createdAt: number; + recipeUserId: string; + }[]; + } + | GeneralErrorResponse + >; + /** + * Remove the credential for the passed credential ID + * + * @param webauthnCredentialId The ID of the credential to remove + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static removeCredential(input: { + webauthnCredentialId: string; + options?: RecipeFunctionOptions; + userContext: any; + }): Promise< + | { + status: "OK"; + } + | GeneralErrorResponse + | { + status: "CREDENTIAL_NOT_FOUND_ERROR"; + fetchResponse: Response; + } + >; + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param webauthnGeneratedOptionsId The ID of the stored options + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param credential The credential to register + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static registerCredential(input: { + webauthnGeneratedOptionsId: string; + recipeUserId: 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; + } + >; static doesBrowserSupportWebAuthn(input: { userContext: any }): Promise< | { status: "OK"; @@ -563,9 +708,13 @@ declare const recoverAccount: typeof RecipeWrapper.recoverAccount; declare const registerCredentialWithSignUp: typeof RecipeWrapper.registerCredentialWithSignUp; declare const authenticateCredentialWithSignIn: typeof RecipeWrapper.authenticateCredentialWithSignIn; declare const registerCredentialWithRecoverAccount: typeof RecipeWrapper.registerCredentialWithRecoverAccount; -declare const registerCredential: typeof RecipeWrapper.registerCredential; +declare const createCredential: typeof RecipeWrapper.createCredential; declare const authenticateCredential: typeof RecipeWrapper.authenticateCredential; declare const doesBrowserSupportWebAuthn: typeof RecipeWrapper.doesBrowserSupportWebAuthn; +declare const listCredentials: typeof RecipeWrapper.listCredentials; +declare const removeCredential: typeof RecipeWrapper.removeCredential; +declare const registerCredential: typeof RecipeWrapper.registerCredential; +declare const createAndRegisterCredentialForSessionUser: typeof RecipeWrapper.createAndRegisterCredentialForSessionUser; export { init, getRegisterOptions, @@ -577,9 +726,13 @@ export { recoverAccount, registerCredentialWithSignUp, authenticateCredentialWithSignIn, - registerCredentialWithRecoverAccount, - registerCredential, + createCredential, authenticateCredential, doesBrowserSupportWebAuthn, RecipeInterface, + listCredentials, + removeCredential, + registerCredential, + createAndRegisterCredentialForSessionUser, + registerCredentialWithRecoverAccount, }; diff --git a/lib/build/recipe/webauthn/index.js b/lib/build/recipe/webauthn/index.js index 27a5b9a7..66865ae7 100644 --- a/lib/build/recipe/webauthn/index.js +++ b/lib/build/recipe/webauthn/index.js @@ -28,10 +28,14 @@ var __assign = return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.doesBrowserSupportWebAuthn = - exports.authenticateCredential = +exports.registerCredentialWithRecoverAccount = + exports.createAndRegisterCredentialForSessionUser = exports.registerCredential = - exports.registerCredentialWithRecoverAccount = + exports.removeCredential = + exports.listCredentials = + exports.doesBrowserSupportWebAuthn = + exports.authenticateCredential = + exports.createCredential = exports.authenticateCredentialWithSignIn = exports.registerCredentialWithSignUp = exports.recoverAccount = @@ -194,7 +198,7 @@ var RecipeWrapper = /** @class */ (function () { ); }; /** - * Register credential with the passed options by using native webauthn functions. + * Creates the credential with the passed options by using native webauthn functions. * * It uses `@simplewebauthn/browser` to make the webauthn calls. * @@ -202,8 +206,8 @@ var RecipeWrapper = /** @class */ (function () { * * @returns `{ status: "OK", ...}` if successful along with registration response received */ - RecipeWrapper.registerCredential = function (input) { - return recipe_1.default.getInstanceOrThrow().recipeImplementation.registerCredential(input); + RecipeWrapper.createCredential = function (input) { + return recipe_1.default.getInstanceOrThrow().recipeImplementation.createCredential(input); }; /** * Authenticate the credential with the passed options by using native webauthn functions. @@ -277,6 +281,76 @@ var RecipeWrapper = /** @class */ (function () { }) ); }; + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param email Email of the WebAuthn user to register the credential for + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation} + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + RecipeWrapper.createAndRegisterCredentialForSessionUser = function (input) { + return recipe_1.default.getInstanceOrThrow().recipeImplementation.createAndRegisterCredentialForSessionUser( + __assign(__assign({}, input), { + userContext: input === null || input === void 0 ? void 0 : input.userContext, + }) + ); + }; + /** + * List the credentials for the user + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful along with a list of the user's credentials + */ + RecipeWrapper.listCredentials = function (input) { + return recipe_1.default.getInstanceOrThrow().recipeImplementation.listCredentials( + __assign(__assign({}, input), { + userContext: input === null || input === void 0 ? void 0 : input.userContext, + }) + ); + }; + /** + * Remove the credential for the passed credential ID + * + * @param webauthnCredentialId The ID of the credential to remove + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + RecipeWrapper.removeCredential = function (input) { + return recipe_1.default.getInstanceOrThrow().recipeImplementation.removeCredential( + __assign(__assign({}, input), { + userContext: input === null || input === void 0 ? void 0 : input.userContext, + }) + ); + }; + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param webauthnGeneratedOptionsId The ID of the stored options + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param credential The credential to register + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + RecipeWrapper.registerCredential = function (input) { + return recipe_1.default.getInstanceOrThrow().recipeImplementation.registerCredential(input); + }; RecipeWrapper.doesBrowserSupportWebAuthn = function (input) { return recipe_1.default.getInstanceOrThrow().recipeImplementation.doesBrowserSupportWebAuthn(input); }; @@ -305,9 +379,17 @@ var authenticateCredentialWithSignIn = RecipeWrapper.authenticateCredentialWithS exports.authenticateCredentialWithSignIn = authenticateCredentialWithSignIn; var registerCredentialWithRecoverAccount = RecipeWrapper.registerCredentialWithRecoverAccount; exports.registerCredentialWithRecoverAccount = registerCredentialWithRecoverAccount; -var registerCredential = RecipeWrapper.registerCredential; -exports.registerCredential = registerCredential; +var createCredential = RecipeWrapper.createCredential; +exports.createCredential = createCredential; var authenticateCredential = RecipeWrapper.authenticateCredential; exports.authenticateCredential = authenticateCredential; var doesBrowserSupportWebAuthn = RecipeWrapper.doesBrowserSupportWebAuthn; exports.doesBrowserSupportWebAuthn = doesBrowserSupportWebAuthn; +var listCredentials = RecipeWrapper.listCredentials; +exports.listCredentials = listCredentials; +var removeCredential = RecipeWrapper.removeCredential; +exports.removeCredential = removeCredential; +var registerCredential = RecipeWrapper.registerCredential; +exports.registerCredential = registerCredential; +var createAndRegisterCredentialForSessionUser = RecipeWrapper.createAndRegisterCredentialForSessionUser; +exports.createAndRegisterCredentialForSessionUser = createAndRegisterCredentialForSessionUser; diff --git a/lib/build/recipe/webauthn/recipeImplementation.js b/lib/build/recipe/webauthn/recipeImplementation.js index 50cce337..242702bc 100644 --- a/lib/build/recipe/webauthn/recipeImplementation.js +++ b/lib/build/recipe/webauthn/recipeImplementation.js @@ -533,7 +533,7 @@ function getRecipeImplementation(recipeImplInput) { }); }); }, - registerCredential: function (_a) { + createCredential: function (_a) { var registrationOptions = _a.registrationOptions; return __awaiter(this, void 0, void 0, function () { var registrationResponse, error_1; @@ -584,7 +584,7 @@ function getRecipeImplementation(recipeImplInput) { options = _a.options, userContext = _a.userContext; return __awaiter(this, void 0, void 0, function () { - var registrationOptions, registerCredentialResponse; + var registrationOptions, createCredentialResponse; return __generator(this, function (_b) { switch (_b.label) { case 0: @@ -616,21 +616,21 @@ function getRecipeImplementation(recipeImplInput) { } return [ 4 /*yield*/, - this.registerCredential({ + this.createCredential({ registrationOptions: registrationOptions, userContext: userContext, }), ]; case 2: - registerCredentialResponse = _b.sent(); - if (registerCredentialResponse.status !== "OK") { - return [2 /*return*/, registerCredentialResponse]; + createCredentialResponse = _b.sent(); + if (createCredentialResponse.status !== "OK") { + return [2 /*return*/, createCredentialResponse]; } return [ 4 /*yield*/, this.signUp({ webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, - credential: registerCredentialResponse.registrationResponse, + credential: createCredentialResponse.registrationResponse, shouldTryLinkingWithSessionUser: shouldTryLinkingWithSessionUser, options: options, userContext: userContext, @@ -740,7 +740,7 @@ function getRecipeImplementation(recipeImplInput) { options = _a.options, userContext = _a.userContext; return __awaiter(this, void 0, void 0, function () { - var registrationOptions, registerCredentialResponse; + var registrationOptions, createCredentialResponse; return __generator(this, function (_b) { switch (_b.label) { case 0: @@ -774,22 +774,22 @@ function getRecipeImplementation(recipeImplInput) { } return [ 4 /*yield*/, - this.registerCredential({ + this.createCredential({ registrationOptions: registrationOptions, userContext: userContext, }), ]; case 2: - registerCredentialResponse = _b.sent(); - if (registerCredentialResponse.status !== "OK") { - return [2 /*return*/, registerCredentialResponse]; + createCredentialResponse = _b.sent(); + if (createCredentialResponse.status !== "OK") { + return [2 /*return*/, createCredentialResponse]; } return [ 4 /*yield*/, this.recoverAccount({ token: recoverAccountToken, webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, - credential: registerCredentialResponse.registrationResponse, + credential: createCredentialResponse.registrationResponse, options: options, userContext: userContext, }), @@ -800,6 +800,225 @@ function getRecipeImplementation(recipeImplInput) { }); }); }, + createAndRegisterCredentialForSessionUser: function (_a) { + var recipeUserId = _a.recipeUserId, + email = _a.email, + options = _a.options, + userContext = _a.userContext; + return __awaiter(this, void 0, void 0, function () { + var registrationOptions, createCredentialResponse; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + return [ + 4 /*yield*/, + this.getRegisterOptions({ options: options, userContext: userContext, email: email }), + ]; + case 1: + registrationOptions = _b.sent(); + if ( + (registrationOptions === null || registrationOptions === void 0 + ? void 0 + : 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 === null || registrationOptions === void 0 + ? void 0 + : registrationOptions.status) === "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR" + ) { + throw new Error( + "Got `RECOVER_ACCOUNT_TOKEN_INVALID_ERROR` status that should never happen" + ); + } + return [2 /*return*/, registrationOptions]; + } + return [ + 4 /*yield*/, + this.createCredential({ + registrationOptions: registrationOptions, + userContext: userContext, + }), + ]; + case 2: + createCredentialResponse = _b.sent(); + if (createCredentialResponse.status !== "OK") { + return [2 /*return*/, createCredentialResponse]; + } + return [ + 4 /*yield*/, + this.registerCredential({ + webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, + recipeUserId: recipeUserId, + credential: createCredentialResponse.registrationResponse, + options: options, + userContext: userContext, + }), + ]; + case 3: + // We should have a valid registration response for the passed credentials + // and we are good to go ahead and verify them. + return [2 /*return*/, _b.sent()]; + } + }); + }); + }, + listCredentials: function (_a) { + var options = _a.options, + userContext = _a.userContext; + return __awaiter(this, void 0, void 0, function () { + var _b, jsonBody, fetchResponse, _c, _d; + var _e, _f; + return __generator(this, function (_g) { + switch (_g.label) { + case 0: + _d = (_c = querier).get; + _e = { + path: "//webauthn/credential/list", + }; + _f = {}; + return [ + 4 /*yield*/, + recipe_1.default.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + }), + ]; + case 1: + return [ + 4 /*yield*/, + _d.apply(_c, [ + ((_e.pathParams = ((_f.tenantId = _g.sent() || "public"), _f)), _e), + {}, + querier_1.default.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "LIST_CREDENTIALS", + options: options, + userContext: userContext, + }), + querier_1.default.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "LIST_CREDENTIALS", + userContext: userContext, + }), + ]), + ]; + case 2: + (_b = _g.sent()), (jsonBody = _b.jsonBody), (fetchResponse = _b.fetchResponse); + return [2 /*return*/, __assign(__assign({}, jsonBody), { fetchResponse: fetchResponse })]; + } + }); + }); + }, + removeCredential: function (_a) { + var webauthnCredentialId = _a.webauthnCredentialId, + options = _a.options, + userContext = _a.userContext; + return __awaiter(this, void 0, void 0, function () { + var _b, jsonBody, fetchResponse, _c, _d; + var _e, _f; + return __generator(this, function (_g) { + switch (_g.label) { + case 0: + _d = (_c = querier).post; + _e = { + path: "//webauthn/credential/remove", + }; + _f = {}; + return [ + 4 /*yield*/, + recipe_1.default.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + }), + ]; + case 1: + return [ + 4 /*yield*/, + _d.apply(_c, [ + ((_e.pathParams = ((_f.tenantId = _g.sent() || "public"), _f)), _e), + { + body: { + webauthnCredentialId: webauthnCredentialId, + }, + }, + querier_1.default.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "REMOVE_CREDENTIAL", + options: options, + userContext: userContext, + }), + querier_1.default.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "REMOVE_CREDENTIAL", + userContext: userContext, + }), + ]), + ]; + case 2: + (_b = _g.sent()), (jsonBody = _b.jsonBody), (fetchResponse = _b.fetchResponse); + return [2 /*return*/, __assign(__assign({}, jsonBody), { fetchResponse: fetchResponse })]; + } + }); + }); + }, + registerCredential: function (_a) { + var webauthnGeneratedOptionsId = _a.webauthnGeneratedOptionsId, + recipeUserId = _a.recipeUserId, + credential = _a.credential, + options = _a.options, + userContext = _a.userContext; + return __awaiter(this, void 0, void 0, function () { + var body, _b, jsonBody, fetchResponse, _c, _d; + var _e, _f; + return __generator(this, function (_g) { + switch (_g.label) { + case 0: + body = { + webauthnGeneratedOptionsId: webauthnGeneratedOptionsId, + recipeUserId: recipeUserId, + credential: credential, + }; + _d = (_c = querier).post; + _e = { + path: "//webauthn/credential", + }; + _f = {}; + return [ + 4 /*yield*/, + recipe_1.default.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + }), + ]; + case 1: + return [ + 4 /*yield*/, + _d.apply(_c, [ + ((_e.pathParams = ((_f.tenantId = _g.sent() || "public"), _f)), _e), + { + body: body, + }, + querier_1.default.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "REGISTER_CREDENTIAL", + options: options, + userContext: userContext, + }), + querier_1.default.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "REGISTER_CREDENTIAL", + userContext: userContext, + }), + ]), + ]; + case 2: + (_b = _g.sent()), (jsonBody = _b.jsonBody), (fetchResponse = _b.fetchResponse); + return [2 /*return*/, __assign(__assign({}, jsonBody), { fetchResponse: fetchResponse })]; + } + }); + }); + }, doesBrowserSupportWebAuthn: function () { return __awaiter(_this, void 0, void 0, function () { var isPlatformAuthenticatorAvailable, error_3; diff --git a/lib/build/recipe/webauthn/types.d.ts b/lib/build/recipe/webauthn/types.d.ts index 91f751c2..fcf5b9d7 100644 --- a/lib/build/recipe/webauthn/types.d.ts +++ b/lib/build/recipe/webauthn/types.d.ts @@ -18,7 +18,10 @@ export declare type PreAndPostAPIHookAction = | "SIGN_IN" | "EMAIL_EXISTS" | "GENERATE_RECOVER_ACCOUNT_TOKEN" - | "RECOVER_ACCOUNT"; + | "RECOVER_ACCOUNT" + | "LIST_CREDENTIALS" + | "REMOVE_CREDENTIAL" + | "REGISTER_CREDENTIAL"; export declare type PreAPIHookContext = RecipePreAPIHookContext; export declare type PostAPIHookContext = RecipePostAPIHookContext; export declare type ResidentKey = "required" | "preferred" | "discouraged"; @@ -254,7 +257,7 @@ export declare type RecipeInterface = { fetchResponse: Response; } >; - registerCredential: (input: { + createCredential: (input: { registrationOptions: Omit; userContext: any; }) => Promise< @@ -428,6 +431,113 @@ export declare type RecipeInterface = { error: any; } >; + createAndRegisterCredentialForSessionUser: (input: { + recipeUserId: string; + email: string; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | 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; + } + >; + listCredentials: (input: { options?: RecipeFunctionOptions; userContext: any }) => Promise< + | { + status: "OK"; + credentials: { + webauthnCredentialId: string; + relyingPartyId: string; + createdAt: number; + recipeUserId: string; + }[]; + fetchResponse: Response; + } + | GeneralErrorResponse + >; + removeCredential: (input: { + webauthnCredentialId: string; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | GeneralErrorResponse + | { + status: "CREDENTIAL_NOT_FOUND_ERROR"; + fetchResponse: Response; + } + >; + registerCredential: (input: { + webauthnGeneratedOptionsId: string; + recipeUserId: string; + credential: RegistrationResponseJSON; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | GeneralErrorResponse + | { + status: "REGISTER_CREDENTIAL_NOT_ALLOWED"; + reason?: string; + fetchResponse: Response; + } + | { + status: "INVALID_CREDENTIALS_ERROR"; + fetchResponse: Response; + } + | { + status: "OPTIONS_NOT_FOUND_ERROR"; + fetchResponse: Response; + } + | { + status: "INVALID_OPTIONS_ERROR"; + fetchResponse: Response; + } + | { + status: "INVALID_AUTHENTICATOR_ERROR"; + reason?: string; + fetchResponse: Response; + } + >; doesBrowserSupportWebAuthn: (input: { userContext: any }) => Promise< | { status: "OK"; diff --git a/lib/build/sdk/paths.d.ts b/lib/build/sdk/paths.d.ts index 903c534a..f034197f 100644 --- a/lib/build/sdk/paths.d.ts +++ b/lib/build/sdk/paths.d.ts @@ -1,6 +1,7 @@ import { paths as pathsV3_1 } from "./versions/3.1/schema"; import { paths as pathsV4_0 } from "./versions/4.0/schema"; import { paths as pathsV4_1 } from "./versions/4.1/schema"; +import { paths as pathsV4_2 } from "./versions/4.2/schema"; declare type MergeMethods = { [K in keyof M1 | keyof M2]: K extends keyof M1 ? K extends keyof M2 @@ -26,5 +27,5 @@ declare type MergeManyPaths[]> = T extends [infer : First : never : {}; -export declare type paths = MergeManyPaths<[pathsV3_1, pathsV4_0, pathsV4_1]>; +export declare type paths = MergeManyPaths<[pathsV3_1, pathsV4_0, pathsV4_1, pathsV4_2]>; export {}; diff --git a/lib/ts/recipe/webauthn/index.ts b/lib/ts/recipe/webauthn/index.ts index 10fb68e3..ba4d1626 100644 --- a/lib/ts/recipe/webauthn/index.ts +++ b/lib/ts/recipe/webauthn/index.ts @@ -317,7 +317,7 @@ export default class RecipeWrapper { } /** - * Register credential with the passed options by using native webauthn functions. + * Creates the credential with the passed options by using native webauthn functions. * * It uses `@simplewebauthn/browser` to make the webauthn calls. * @@ -325,7 +325,7 @@ export default class RecipeWrapper { * * @returns `{ status: "OK", ...}` if successful along with registration response received */ - static registerCredential(input: { + static createCredential(input: { registrationOptions: Omit; userContext: any; }): Promise< @@ -337,7 +337,7 @@ export default class RecipeWrapper { | { status: "FAILED_TO_REGISTER_USER"; error: any } | { status: "WEBAUTHN_NOT_SUPPORTED"; error: any } > { - return Recipe.getInstanceOrThrow().recipeImplementation.registerCredential(input); + return Recipe.getInstanceOrThrow().recipeImplementation.createCredential(input); } /** @@ -508,6 +508,128 @@ export default class RecipeWrapper { }); } + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param email Email of the WebAuthn user to register the credential for + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param userContext (OPTIONAL) Refer to {@link https://supertokens.com/docs/emailpassword/advanced-customizations/user-context the documentation} + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static createAndRegisterCredentialForSessionUser(input: { + email: string; + recipeUserId: string; + options?: RecipeFunctionOptions; + userContext: any; + }): Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | 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 Recipe.getInstanceOrThrow().recipeImplementation.createAndRegisterCredentialForSessionUser({ + ...input, + userContext: input?.userContext, + }); + } + + /** + * List the credentials for the user + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful along with a list of the user's credentials + */ + static listCredentials(input: { options?: RecipeFunctionOptions; userContext: any }): Promise< + | { + status: "OK"; + credentials: { + webauthnCredentialId: string; + relyingPartyId: string; + createdAt: number; + recipeUserId: string; + }[]; + } + | GeneralErrorResponse + > { + return Recipe.getInstanceOrThrow().recipeImplementation.listCredentials({ + ...input, + userContext: input?.userContext, + }); + } + + /** + * Remove the credential for the passed credential ID + * + * @param webauthnCredentialId The ID of the credential to remove + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static removeCredential(input: { + webauthnCredentialId: string; + options?: RecipeFunctionOptions; + userContext: any; + }): Promise< + { status: "OK" } | GeneralErrorResponse | { status: "CREDENTIAL_NOT_FOUND_ERROR"; fetchResponse: Response } + > { + return Recipe.getInstanceOrThrow().recipeImplementation.removeCredential({ + ...input, + userContext: input?.userContext, + }); + } + + /** + * Register the new device with the passed user details + * + * It uses `@simplewebauthn/browser` to make the webauthn calls. + * + * @param webauthnGeneratedOptionsId The ID of the stored options + * + * @param recipeUserId The recipe user ID of the webauthn user to register the credential for + * + * @param credential The credential to register + * + * @param options (OPTIONAL) Use this to configure additional properties (for example pre api hooks) + * + * @returns `{ status: "OK", ...}` if successful + */ + static registerCredential(input: { + webauthnGeneratedOptionsId: string; + recipeUserId: 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 Recipe.getInstanceOrThrow().recipeImplementation.registerCredential(input); + } + static doesBrowserSupportWebAuthn(input: { userContext: any }): Promise< | { status: "OK"; @@ -534,9 +656,13 @@ const recoverAccount = RecipeWrapper.recoverAccount; const registerCredentialWithSignUp = RecipeWrapper.registerCredentialWithSignUp; const authenticateCredentialWithSignIn = RecipeWrapper.authenticateCredentialWithSignIn; const registerCredentialWithRecoverAccount = RecipeWrapper.registerCredentialWithRecoverAccount; -const registerCredential = RecipeWrapper.registerCredential; +const createCredential = RecipeWrapper.createCredential; const authenticateCredential = RecipeWrapper.authenticateCredential; const doesBrowserSupportWebAuthn = RecipeWrapper.doesBrowserSupportWebAuthn; +const listCredentials = RecipeWrapper.listCredentials; +const removeCredential = RecipeWrapper.removeCredential; +const registerCredential = RecipeWrapper.registerCredential; +const createAndRegisterCredentialForSessionUser = RecipeWrapper.createAndRegisterCredentialForSessionUser; export { init, @@ -549,9 +675,13 @@ export { recoverAccount, registerCredentialWithSignUp, authenticateCredentialWithSignIn, - registerCredentialWithRecoverAccount, - registerCredential, + createCredential, authenticateCredential, doesBrowserSupportWebAuthn, RecipeInterface, + listCredentials, + removeCredential, + registerCredential, + createAndRegisterCredentialForSessionUser, + registerCredentialWithRecoverAccount, }; diff --git a/lib/ts/recipe/webauthn/recipeImplementation.ts b/lib/ts/recipe/webauthn/recipeImplementation.ts index 1c6a6d56..45d75d27 100644 --- a/lib/ts/recipe/webauthn/recipeImplementation.ts +++ b/lib/ts/recipe/webauthn/recipeImplementation.ts @@ -26,6 +26,7 @@ import { startAuthentication, startRegistration, } from "@simplewebauthn/browser"; +import { paths } from "../../sdk/paths"; export default function getRecipeImplementation( recipeImplInput: RecipeImplementationInput @@ -290,7 +291,7 @@ export default function getRecipeImplementation( fetchResponse, }; }, - registerCredential: async function ({ registrationOptions }) { + createCredential: async function ({ registrationOptions }) { let registrationResponse: RegistrationResponseJSON; try { registrationResponse = await startRegistration({ optionsJSON: registrationOptions }); @@ -339,16 +340,16 @@ export default function getRecipeImplementation( } // We should have received a valid registration options response. - const registerCredentialResponse = await this.registerCredential({ registrationOptions, userContext }); - if (registerCredentialResponse.status !== "OK") { - return registerCredentialResponse; + const createCredentialResponse = await this.createCredential({ registrationOptions, userContext }); + if (createCredentialResponse.status !== "OK") { + return createCredentialResponse; } // 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: registerCredentialResponse.registrationResponse, + credential: createCredentialResponse.registrationResponse, shouldTryLinkingWithSessionUser, options, userContext, @@ -422,22 +423,166 @@ export default function getRecipeImplementation( } // We should have received a valid registration options response. - const registerCredentialResponse = await this.registerCredential({ + const createCredentialResponse = await this.createCredential({ registrationOptions, userContext, }); - if (registerCredentialResponse.status !== "OK") { - return registerCredentialResponse; + if (createCredentialResponse.status !== "OK") { + return createCredentialResponse; } return await this.recoverAccount({ token: recoverAccountToken, webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, - credential: registerCredentialResponse.registrationResponse, + credential: createCredentialResponse.registrationResponse, options, userContext, }); }, + createAndRegisterCredentialForSessionUser: async function ({ recipeUserId, email, options, userContext }) { + // Get the registration options by using the passed email ID. + const registrationOptions = await this.getRegisterOptions({ 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. + const createCredentialResponse = await this.createCredential({ registrationOptions, userContext }); + if (createCredentialResponse.status !== "OK") { + return createCredentialResponse; + } + + // We should have a valid registration response for the passed credentials + // and we are good to go ahead and verify them. + return await this.registerCredential({ + webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId, + recipeUserId, + credential: createCredentialResponse.registrationResponse, + options, + userContext, + }); + }, + listCredentials: async function ({ options, userContext }) { + const { jsonBody, fetchResponse } = await querier.get( + { + path: "//webauthn/credential/list", + pathParams: { + tenantId: + (await Multitenancy.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + })) || "public", + }, + }, + {}, + Querier.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "LIST_CREDENTIALS", + options: options, + userContext: userContext, + }), + Querier.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "LIST_CREDENTIALS", + userContext: userContext, + }) + ); + + return { + ...jsonBody, + fetchResponse, + }; + }, + removeCredential: async function ({ webauthnCredentialId, options, userContext }) { + const { jsonBody, fetchResponse } = await querier.post( + { + path: "//webauthn/credential/remove", + pathParams: { + tenantId: + (await Multitenancy.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + })) || "public", + }, + }, + { + body: { + webauthnCredentialId, + }, + }, + Querier.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "REMOVE_CREDENTIAL", + options: options, + userContext: userContext, + }), + Querier.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "REMOVE_CREDENTIAL", + userContext: userContext, + }) + ); + + return { + ...jsonBody, + fetchResponse, + }; + }, + registerCredential: async function ({ + webauthnGeneratedOptionsId, + recipeUserId, + credential, + options, + userContext, + }) { + // This weird trick is required because otherwise TS will complain since we added the new prop in 4.2, but still support 4.1 + // It doesn't get picked up somehow... + // TODO: Figure out why merging doesn't work right in this case + const body: Required< + paths["//webauthn/credential"]["post"] + >["requestBody"]["content"]["application/json"] = { + webauthnGeneratedOptionsId, + recipeUserId, + credential, + }; + const { jsonBody, fetchResponse } = await querier.post( + { + path: "//webauthn/credential", + pathParams: { + tenantId: + (await Multitenancy.getInstanceOrThrow().recipeImplementation.getTenantId({ + userContext: userContext, + })) || "public", + }, + }, + { + body, + }, + Querier.preparePreAPIHook({ + recipePreAPIHook: recipeImplInput.preAPIHook, + action: "REGISTER_CREDENTIAL", + options: options, + userContext: userContext, + }), + Querier.preparePostAPIHook({ + recipePostAPIHook: recipeImplInput.postAPIHook, + action: "REGISTER_CREDENTIAL", + userContext: userContext, + }) + ); + + return { + ...jsonBody, + fetchResponse, + }; + }, doesBrowserSupportWebAuthn: async () => { try { const isPlatformAuthenticatorAvailable = await platformAuthenticatorIsAvailable(); diff --git a/lib/ts/recipe/webauthn/types.ts b/lib/ts/recipe/webauthn/types.ts index afa8a8e1..2dad9f16 100644 --- a/lib/ts/recipe/webauthn/types.ts +++ b/lib/ts/recipe/webauthn/types.ts @@ -34,7 +34,10 @@ export type PreAndPostAPIHookAction = | "SIGN_IN" | "EMAIL_EXISTS" | "GENERATE_RECOVER_ACCOUNT_TOKEN" - | "RECOVER_ACCOUNT"; + | "RECOVER_ACCOUNT" + | "LIST_CREDENTIALS" + | "REMOVE_CREDENTIAL" + | "REGISTER_CREDENTIAL"; export type PreAPIHookContext = RecipePreAPIHookContext; export type PostAPIHookContext = RecipePostAPIHookContext; @@ -233,7 +236,7 @@ export type RecipeInterface = { | { status: "INVALID_OPTIONS_ERROR"; fetchResponse: Response } | { status: "INVALID_AUTHENTICATOR_ERROR"; reason: string; fetchResponse: Response } >; - registerCredential: (input: { + createCredential: (input: { registrationOptions: Omit; userContext: any; }) => Promise< @@ -332,6 +335,74 @@ export type RecipeInterface = { | { status: "FAILED_TO_REGISTER_USER"; error: any } | { status: "WEBAUTHN_NOT_SUPPORTED"; error: any } >; + createAndRegisterCredentialForSessionUser: (input: { + recipeUserId: string; + email: string; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | 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 } + >; + listCredentials: (input: { options?: RecipeFunctionOptions; userContext: any }) => Promise< + | { + status: "OK"; + credentials: { + webauthnCredentialId: string; + relyingPartyId: string; + createdAt: number; + recipeUserId: string; + }[]; + fetchResponse: Response; + } + | GeneralErrorResponse + >; + removeCredential: (input: { + webauthnCredentialId: string; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | GeneralErrorResponse + | { status: "CREDENTIAL_NOT_FOUND_ERROR"; fetchResponse: Response } + >; + registerCredential: (input: { + webauthnGeneratedOptionsId: string; + recipeUserId: string; + credential: RegistrationResponseJSON; + options?: RecipeFunctionOptions; + userContext: any; + }) => Promise< + | { + status: "OK"; + fetchResponse: Response; + } + | GeneralErrorResponse + | { + status: "REGISTER_CREDENTIAL_NOT_ALLOWED"; + reason?: string; + fetchResponse: Response; + } + | { status: "INVALID_CREDENTIALS_ERROR"; fetchResponse: Response } + | { status: "OPTIONS_NOT_FOUND_ERROR"; fetchResponse: Response } + | { status: "INVALID_OPTIONS_ERROR"; fetchResponse: Response } + | { status: "INVALID_AUTHENTICATOR_ERROR"; reason?: string; fetchResponse: Response } + >; doesBrowserSupportWebAuthn: (input: { userContext: any }) => Promise< | { status: "OK"; diff --git a/lib/ts/sdk/paths.ts b/lib/ts/sdk/paths.ts index 6975e1dc..62b8b011 100644 --- a/lib/ts/sdk/paths.ts +++ b/lib/ts/sdk/paths.ts @@ -2,6 +2,7 @@ import { paths as pathsV3_1 } from "./versions/3.1/schema"; import { paths as pathsV4_0 } from "./versions/4.0/schema"; import { paths as pathsV4_1 } from "./versions/4.1/schema"; +import { paths as pathsV4_2 } from "./versions/4.2/schema"; type MergeMethods = { [K in keyof M1 | keyof M2]: K extends keyof M1 @@ -31,4 +32,4 @@ type MergeManyPaths[]> = T extends [infer First, . : never : {}; -export type paths = MergeManyPaths<[pathsV3_1, pathsV4_0, pathsV4_1]>; +export type paths = MergeManyPaths<[pathsV3_1, pathsV4_0, pathsV4_1, pathsV4_2]>; diff --git a/lib/ts/sdk/versions/4.1/schema.d.ts b/lib/ts/sdk/versions/4.1/schema.d.ts index 5adaa24a..fdc90ead 100644 --- a/lib/ts/sdk/versions/4.1/schema.d.ts +++ b/lib/ts/sdk/versions/4.1/schema.d.ts @@ -3631,15 +3631,11 @@ export interface operations { | components["schemas"]["generalErrorResponse"] | { /** @enum {string} */ - status: - | "INVALID_CREDENTIALS_ERROR" - | "OPTIONS_NOT_FOUND_ERROR" - | "INVALID_OPTIONS_ERROR" - | "INVALID_AUTHENTICATOR_ERROR"; + status: "INVALID_CREDENTIALS_ERROR" | "OPTIONS_NOT_FOUND_ERROR" | "INVALID_OPTIONS_ERROR"; } | { /** @enum {string} */ - status: "REGISTER_CREDENTIAL_NOT_ALLOWED" | "INVALID_AUTHENTICATOR_ERRORp"; + status: "REGISTER_CREDENTIAL_NOT_ALLOWED" | "INVALID_AUTHENTICATOR_ERROR"; /** @example Register credential not allowed */ reason?: string; }; diff --git a/lib/ts/sdk/versions/4.2/schema.d.ts b/lib/ts/sdk/versions/4.2/schema.d.ts new file mode 100644 index 00000000..d5d24482 --- /dev/null +++ b/lib/ts/sdk/versions/4.2/schema.d.ts @@ -0,0 +1,3919 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/mfa/info": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** @description Returns information about the auth factors of the current user and refreshes the related session claim + * */ + put: operations["getMFAInfo"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/totp/device/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List the TOTP devices of the current user + * */ + get: operations["listTOTPdevices"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/totp/device": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Creates an unverified totp device + * */ + post: operations["createTOTPDevice"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/totp/device/remove": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Removes a totp device + * */ + post: operations["removeTOTPDevice"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/totp/device/verify": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Checks that the TOTP sent in the body belongs to the totp device (specified by deviceName, belonging to the session user) + * */ + post: operations["verifyTOTPDevice"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/totp/verify": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Checks that the TOTP sent in the body belongs to a verified totp device of the session user + * */ + post: operations["verifyTOTP"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signinup/code": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Start sign in/up process with passwordless + * */ + post: operations["passwordlessSignInUpStart"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signinup/code/resend": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Resend passwordless code + * */ + post: operations["passwordlessSignInUpResend"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signinup/code/consume": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Finish sign in/up process with passwordless + * */ + post: operations["passwordlessSignInUpConsume"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signup/email/exists\u2800\u2800": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * @deprecated + * @description Check if an email exists + * Note that there is an invisible character at the end of the path, this was to avoid a conflict with the OpenAPI spec. + * + */ + get: operations["passwordlessEmailExistsDepr"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//passwordless/email/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Check if an email exists + * */ + get: operations["passwordlessEmailExists"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signup/phoneNumber/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * @deprecated + * @description Check if a phone number exists + * + */ + get: operations["passwordlessPhoneNumberExistsDepr"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//passwordless/phonenumber/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Check if a phone number exists + * */ + get: operations["passwordlessPhoneNumberExists"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/signout": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Logout user + * */ + post: operations["signout"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/session/refresh": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Refresh the user session + * */ + post: operations["refresh"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signin": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Signin a user with email ID and password + * */ + post: operations["signIn"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Signup a user with email ID and password + * */ + post: operations["signUp"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signup/email/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * @deprecated + * @description Check if an email exists + * + */ + get: operations["emailExistsDepr"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//emailpassword/email/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Check if an email exists + * */ + get: operations["emailExists"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//user/password/reset/token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Generate a new reset password token for this user + * */ + post: operations["passwordResetToken"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//user/password/reset": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reset a password using password reset token + * */ + post: operations["passwordReset"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//signinup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Signin/up a user + * */ + post: operations["signInUp"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//authorisationurl": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get the thirdparty provider's authorisation URL to which the user should be redirected to. + * */ + get: operations["authorisationUrl"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//loginmethods": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get enabled login methods: Returns recipes with their enabled setting and recipe specific configuration. + * */ + get: operations["loginmethods"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/callback/apple": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Handles sign in with the apple. + * */ + post: operations["thirdPartyCallbackApple"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/user/email/verify/token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Send email verification email + * */ + post: operations["verifyEmailToken"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//user/email/verify": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Verify an email + * */ + post: operations["verifyEmail"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/user/email/verify": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Checks if an email is verified and adds this information into the access token payload as well + * */ + get: operations["getVerifyEmail"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/jwt/jwks.json": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get all JSON web keys for JWT verification + * */ + get: operations["getJWKS"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/.well-known/openid-configuration": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Get OpenID discovery configuration + * */ + get: operations["getOpenIdDiscoveryConfiguration"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/login": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Continues the OAuth2 login flow after the login page + * */ + get: operations["oauthLoginGET"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/auth": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Starts the OAuth2 login flow - for a detailed description of all input parameters please see the OAuth2 and OpenID Connect Core specs + * */ + get: operations["oauthAuthGET"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Exchanges an OAuth2 grant (e.g.: authorization code) for an access token (and optionally a refresh/id token) - for a detailed description of all input parameters please see the OAuth2 and OpenID Connect Core specs + * */ + post: operations["oauthTokenPOST"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/userinfo": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Retrieves user information based on the access token passed in the authorization header + * */ + get: operations["oauthUserInfoGET"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/revoke": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Revokes an access/refresh token - the client id and secret can also be provided in an authorization header using the Basic scheme + * */ + post: operations["oauthRevokePOST"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/introspect": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Introspects an access/refresh token + * */ + post: operations["oauthIntrospectPOST"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/end_session": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Redirects the user to a page where they can log out and revoke the oauth tokens + * */ + get: operations["oauthEndSessionGET"]; + put?: never; + /** @description Redirects the user to a page where they can log out and revoke the oauth tokens - for a detailed description of input parameters please see the user initiated logout spec + * */ + post: operations["oauthEndSessionPOST"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/login/info": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Retrieves information about the OAuth2 login + * */ + get: operations["oauthLoginInfoGET"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/oauth/logout": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Logs out the user and revokes the access/refresh tokens based on the id_token_hint passed to the end_session endpoint + * */ + post: operations["oauthLogoutPOST"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/example": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description API endpoint in your application, checked with `verifySession` + * */ + get: operations["exampleAppAPI"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/options/register": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Get WebAuthn registration options for a user + * */ + post: operations["webauthnRegisterOptions"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/options/signin": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Get WebAuthn sign in options + * */ + post: operations["webauthnSignInOptions"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/signup": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign up a user with WebAuthn + * */ + post: operations["webauthnSignUp"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/signin": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Sign in a user with WebAuthn + * */ + post: operations["webauthnSignIn"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/recover/account/token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Generate a recovery token for a WebAuthn account + * */ + post: operations["webauthnGenerateRecoverAccountToken"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/recover/account": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Recover a WebAuthn account + * */ + post: operations["webauthnRecoverAccount"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/credential": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Register a new WebAuthn credential for an existing user + * */ + post: operations["webauthnRegisterCredential"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/credential/remove": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Remove a WebAuthn credential for an existing user + * */ + post: operations["webauthnRemoveCredential"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/credential/list": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description List all WebAuthn credentials for an existing user + * */ + get: operations["webauthnListCredentials"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//webauthn/email/exists": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** @description Check if a WebAuthn email exists + * */ + get: operations["webauthnEmailExists"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//user/webauthn/reset/token": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reset a WebAuthn account + * */ + post: operations["webauthnResetToken"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "//user/webauthn/reset": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** @description Reset a WebAuthn account + * */ + post: operations["webauthnReset"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + /** @enum {string} */ + statusOK: "OK"; + generalErrorResponse: { + /** @enum {string} */ + status: "GENERAL_ERROR"; + message?: string; + }; + /** @example ZTRiOTBjNz...jI5MTZlODkxw */ + token: string; + /** @example ed3164...06c0d; Path=/; Expires=Thu, 30 Sep 2021 06:43:07 GMT; HttpOnly; SameSite=Lax */ + cookie: string; + /** @enum {string} */ + id: "email" | "password"; + /** @example fa7a0841-b533-4478-95533-0fde890c3483 */ + userId: string; + user: { + id: components["schemas"]["userId"]; + /** @example 1638433545183 */ + timeJoined: number; + /** @example true */ + isPrimaryUser: boolean; + webauthn: { + credentialIds: string[]; + }; + tenantIds: string[]; + emails: string[]; + phoneNumbers: string[]; + thirdParty: { + /** @example google */ + id: string; + /** @example rq238mrq2389rvq123213 */ + userId: string; + }[]; + loginMethods: { + /** @enum {string} */ + recipeId: "emailpassword" | "thirdparty" | "passwordless"; + recipeUserId: components["schemas"]["userId"]; + /** @example true */ + verified?: boolean; + tenantIds: string[]; + /** @example 1638433545183 */ + timeJoined: number; + /** @example johndoe@gmail.com */ + email?: string; + /** @example 36201234123 */ + phoneNumber?: string; + thirdParty?: { + /** @example google */ + id: string; + /** @example rq238mrq2389rvq123213 */ + userId: string; + }; + }[]; + }; + /** @example johndoe@gmail.com */ + email: string; + /** @example 0036701234567 */ + phoneNumber: string; + /** + * @description This should be saved on the starting device to enable the manual code entry flow. + * @example TU/52WOcktSv99zqaAZuWJG9BSoS0aRLfCbep8rFEwk= + */ + deviceId: string; + /** + * @description An identifier that used to identify the login attempt/device. + * @example kFmkPQEAJtACiT2w/K8fndEuNm+XozJXSZSlWEr+iGs= + */ + preAuthSessionId: string; + /** @example google */ + thirdPartyId: string; + /** @example true */ + exists: boolean; + /** @example token */ + method: string; + code: components["schemas"]["token"]; + /** @description Can contain random data other than the two listed below */ + authCodeResponse: { + access_token: string; + id_token?: string; + }; + /** @example https://yourdomain.com/callback */ + redirectURI: string; + /** @example web */ + clientType: string; + oAuthTokens: { + /** @example ZTRiOTBjNz...jI5MTZlODkxw */ + access_token?: string; + /** @example ZTRiOTBjNz...jI5MTZlODkxw */ + id_token?: string; + }; + /** @example [ + * { + * "id": "email", + * "value": "johndoe@gmail.com" + * }, + * { + * "id": "password", + * "value": "testPass123" + * } + * ] */ + formFields: { + id: string; + value: string; + }[]; + signInResponse: { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + }; + signInNotAllowedResponse: { + /** @enum {string} */ + status: "SIGN_IN_NOT_ALLOWED"; + /** @example Cannot sign in due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_008) */ + reason?: string; + }; + signupResponse: { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + }; + signUpNotAllowedResponse: { + /** @enum {string} */ + status: "SIGN_UP_NOT_ALLOWED"; + /** @example Cannot sign up due to security reasons. Please try resetting your password, use a different login method or contact support. (ERR_CODE_007) */ + reason?: string; + }; + passwordResetTokenResponse: { + status: components["schemas"]["statusOK"]; + }; + passwordResetNotAllowedResponse: { + /** @enum {string} */ + status: "PASSWORD_RESET_NOT_ALLOWED"; + /** @example Token generation was not done because of account take over risk. Please contact support. (HAS_OTHER_EMAIL_OR_PHONE) */ + reason?: string; + }; + signinupResponse: { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + /** @example true */ + createdNewRecipeUser?: boolean; + }; + passwordResetErrorResponse: { + /** @enum {string} */ + status: "RESET_PASSWORD_INVALID_TOKEN_ERROR"; + }; + passwordResetResponse: { + /** @enum {string} */ + status: "OK"; + }; + fieldErrorResponse: { + /** @enum {string} */ + status: "FIELD_ERROR"; + formFields: { + /** @example email */ + id: string; + /** @example Error Message */ + error: string; + }[]; + }; + wrongCredentialsResponse: { + /** @enum {string} */ + status: "WRONG_CREDENTIALS_ERROR"; + }; + signinupErrorResponse: + | { + /** @enum {string} */ + status: "NO_EMAIL_GIVEN_BY_PROVIDER"; + } + | { + /** @enum {string} */ + status: "SIGN_IN_UP_NOT_ALLOWED"; + /** @example Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE) */ + reason?: string; + }; + /** @enum {string} */ + internalError: "Internal Error"; + /** @enum {string} */ + badRequest: "Bad request"; + /** @enum {string} */ + notFound: "Not Found"; + clientExtensionResults: { + /** @example true */ + appid?: boolean; + credProps?: { + /** @example true */ + rk?: boolean; + }; + /** @example true */ + hmacCreateSecret?: boolean; + }; + registrationPayload: { + /** @example cred_123... */ + id: string; + /** @example base64rawid... */ + rawId: string; + /** @enum {string} */ + authenticatorAttachment?: "platform" | "cross-platform"; + clientExtensionResults?: components["schemas"]["clientExtensionResults"]; + response: { + /** @example base64clientdata... */ + clientDataJSON: string; + /** @example base64attestation... */ + attestationObject: string; + /** @example base64authenticatordata... */ + authenticatorData?: string; + transports?: ("usb" | "nfc" | "ble" | "internal" | "smart-card" | "cable" | "hybrid")[]; + /** @example base64publickey... */ + publicKey?: string; + /** @example -7 */ + publicKeyAlgorithm?: number; + }; + /** @enum {string} */ + type: "public-key"; + }; + authenticationPayload: { + /** @example cred_123... */ + id: string; + /** @example base64rawid... */ + rawId: string; + /** @enum {string} */ + authenticatorAttachment?: "platform" | "cross-platform"; + clientExtensionResults?: components["schemas"]["clientExtensionResults"]; + response: { + /** @example base64clientdata... */ + clientDataJSON: string; + /** @example base64authenticatordata... */ + authenticatorData: string; + /** @example base64signature... */ + signature: string; + /** @example base64userhandle... */ + userHandle?: string; + }; + /** @enum {string} */ + type: "public-key"; + }; + }; + responses: { + /** @description error code 400 */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "text/plain": components["schemas"]["badRequest"]; + }; + }; + /** @description error code 404 */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "text/plain": components["schemas"]["notFound"]; + }; + }; + /** @description error code 500 */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "text/plain": components["schemas"]["internalError"]; + }; + }; + /** @description error code 400 for OAuth2 errors */ + "400-oauth-error": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @example invalid_request */ + error?: string; + /** @example Unsupported grant type: password */ + error_description?: string; + }; + }; + }; + /** @description A claim validation error happened during factor setup */ + "403-factor-setup": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @example invalid claim */ + message?: string; + claimValidationErrors?: { + /** @example st-ev */ + id?: string; + /** @example { + * "message": "wrong value", + * "expectedValue": true, + * "actualValue": false + * } */ + reason?: Record; + }[]; + } + | { + /** @example invalid claim */ + message?: string; + claimValidationErrors?: { + /** @example st-mfa */ + id?: string; + /** @example Completed factors in the session does not satisfy the MFA requirements for auth */ + reason?: string; + }[]; + }; + }; + }; + }; + parameters: { + /** @example session */ + rid: string; + /** @example emailpassword */ + emailPasswordRid: string; + /** @example thirdparty */ + thirdPartyRid: string; + /** @example passwordless */ + passwordlessRid: string; + /** @example emailverification */ + emailVerificationRid: string; + /** @example multitenancy */ + multitenancyRid: string; + /** @example multifactorauth */ + multiFactorAuthRid: string; + /** @example totp */ + totpRid: string; + /** @description This will only be here if enabled by the user. */ + "anti-csrf": components["schemas"]["token"]; + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: string; + email: string; + phoneNumber: string; + /** @example webauthn */ + webauthnRid: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + getMFAInfo: { + parameters: { + query?: never; + header?: { + /** @example multifactorauth */ + rid?: components["parameters"]["multiFactorAuthRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Information about the auth factors of the current user and optionally the session with a refreshed MFA claim */ + 200: { + headers: { + /** @description Sent in cookie-based sessions if the access token is updated */ + "Set-Cookie"?: string; + /** @description Sent in cookie-based sessions if the access token is updated */ + "st-access-token"?: components["schemas"]["token"]; + /** @description Sent if enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + /** @description Sent if the access token is updated */ + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + factors?: { + alreadySetup: string[]; + allowedToSetup: string[]; + next: string[]; + }; + emails?: { + emailpassword?: string[]; + "otp-email"?: string[]; + "link-email"?: string[]; + }; + phoneNumbers?: { + "otp-phone"?: string[]; + "link-phone"?: string[]; + }; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + listTOTPdevices: { + parameters: { + query?: never; + header?: { + /** @example totp */ + rid?: components["parameters"]["totpRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The list of the TOTP devices of the session user */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + devices?: { + /** @example asdf123 */ + name: string; + /** @example 30 */ + period: number; + /** @example 30 */ + skew: number; + /** @example false */ + verified: boolean; + }[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + createTOTPDevice: { + parameters: { + query?: never; + header?: { + /** @example totp */ + rid?: components["parameters"]["totpRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example asdf123 */ + deviceName?: string; + }; + }; + }; + responses: { + /** @description Information about the created (unverified) device. Based on the this, + * the user can add the device to their TOTP app and verify it. + * */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example asfd123 */ + deviceName?: string; + /** @example otpauth://totp/Supertokens:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Supertokens */ + qrCodeString?: string; + /** @example JBSWY3DPEHPK3PXP */ + secret?: string; + } + | { + /** @enum {string} */ + status: "DEVICE_ALREADY_EXISTS_ERROR"; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + removeTOTPDevice: { + parameters: { + query?: never; + header?: { + /** @example totp */ + rid?: components["parameters"]["totpRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example asdf123 */ + deviceName?: string; + }; + }; + }; + responses: { + /** @description Success report */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example true */ + didDeviceExist?: boolean; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + verifyTOTPDevice: { + parameters: { + query?: never; + header?: { + /** @example totp */ + rid?: components["parameters"]["totpRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example 123456 */ + totp?: string; + /** @example asdf123asdf */ + deviceName?: string; + }; + }; + }; + responses: { + /** @description Verification result and optionally the session with a refreshed MFA claim */ + 200: { + headers: { + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "Set-Cookie"?: string; + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "st-access-token"?: components["schemas"]["token"]; + /** @description Sent if enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + /** @description Sent if the access token payload is updated */ + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + wasAlreadyVerified: boolean; + } + | { + /** @enum {string} */ + status: "UNKNOWN_DEVICE_ERROR"; + } + | { + /** @enum {string} */ + status: "INVALID_TOTP_ERROR"; + /** @example 2 */ + currentNumberOfFailedAttempts?: number; + /** @example 5 */ + maxNumberOfFailedAttempts?: number; + } + | { + /** @enum {string} */ + status: "LIMIT_REACHED_ERROR"; + /** @example 30000 */ + retryAfterMs?: number; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + verifyTOTP: { + parameters: { + query?: never; + header?: { + /** @example totp */ + rid?: components["parameters"]["totpRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example 123456 */ + totp?: string; + }; + }; + }; + responses: { + /** @description Verification result and optionally the session with a refreshed MFA claim */ + 200: { + headers: { + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "Set-Cookie"?: string; + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "st-access-token"?: components["schemas"]["token"]; + /** @description Sent if enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + /** @description Sent if the access token payload is updated */ + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | { + /** @enum {string} */ + status: "INVALID_TOTP_ERROR"; + /** @example 2 */ + currentNumberOfFailedAttempts?: number; + /** @example 5 */ + maxNumberOfFailedAttempts?: number; + } + | { + /** @enum {string} */ + status: "LIMIT_REACHED_ERROR"; + /** @example 30000 */ + retryAfterMs?: number; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessSignInUpStart: { + parameters: { + query?: never; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": + | { + email: components["schemas"]["email"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + } + | { + phoneNumber: components["schemas"]["phoneNumber"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Started the passwordless sign in/up process. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + deviceId?: components["schemas"]["deviceId"]; + preAuthSessionId?: components["schemas"]["preAuthSessionId"]; + /** @enum {string} */ + flowType?: "MAGIC_LINK" | "USER_INPUT_CODE_AND_MAGIC_LINK" | "USER_INPUT_CODE"; + } + | { + /** @enum {string} */ + status: "SIGN_IN_UP_NOT_ALLOWED"; + /** @example Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE) */ + reason?: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessSignInUpResend: { + parameters: { + query?: never; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + deviceId: components["schemas"]["deviceId"]; + preAuthSessionId: components["schemas"]["preAuthSessionId"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Started the passwordless sign in/up process. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @enum {string} */ + status: "OK" | "RESTART_FLOW_ERROR"; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessSignInUpConsume: { + parameters: { + query?: never; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": + | { + preAuthSessionId: components["schemas"]["preAuthSessionId"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + /** @example b10lbT_SnDC4flA6Fn7pE5TtG5k5NfigLef4QMBeGA8 */ + linkCode: string; + } + | { + preAuthSessionId: components["schemas"]["preAuthSessionId"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + deviceId: components["schemas"]["deviceId"]; + /** @example 432123 */ + userInputCode: string; + }; + }; + }; + responses: { + /** @description Signin/up a user */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example true */ + createdNewRecipeUser?: boolean; + user?: components["schemas"]["user"]; + } + | { + /** @enum {string} */ + status: "INCORRECT_USER_INPUT_CODE_ERROR" | "EXPIRED_USER_INPUT_CODE_ERROR"; + /** @example 2 */ + failedCodeInputAttemptCount?: number; + /** @example 5 */ + maximumCodeInputAttempts?: number; + } + | { + /** @enum {string} */ + status: "RESTART_FLOW_ERROR"; + } + | { + /** @enum {string} */ + status: "SIGN_IN_UP_NOT_ALLOWED"; + /** @example Cannot sign in / up due to security reasons. Please contact support. (IS_SIGN_IN_ALLOWED_FALSE) */ + reason?: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessEmailExistsDepr: { + parameters: { + query: { + email: components["parameters"]["email"]; + }; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if an email exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessEmailExists: { + parameters: { + query: { + email: components["parameters"]["email"]; + }; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if an email exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessPhoneNumberExistsDepr: { + parameters: { + query: { + phoneNumber: components["parameters"]["phoneNumber"]; + }; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if a phone number exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordlessPhoneNumberExists: { + parameters: { + query: { + phoneNumber: components["parameters"]["phoneNumber"]; + }; + header?: { + /** @example passwordless */ + rid?: components["parameters"]["passwordlessRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if a phone number exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + signout: { + parameters: { + query?: never; + header?: { + /** @example session */ + rid?: components["parameters"]["rid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": Record; + }; + }; + responses: { + /** @description Logout user */ + 200: { + headers: { + "Set-Cookie"?: string; + /** @description Set to an empty string to trigger token clearing in the client SDK */ + "st-access-token"?: string; + /** @description Set to an empty string to trigger token clearing in the client SDK */ + "st-refresh-token"?: string; + "front-token"?: string; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + refresh: { + parameters: { + query?: never; + header?: { + /** @example session */ + rid?: components["parameters"]["rid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Refresh users */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content?: never; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + signIn: { + parameters: { + query?: never; + header?: { + /** @example session */ + rid?: components["parameters"]["rid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + formFields: components["schemas"]["formFields"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Sign in Response */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | components["schemas"]["signInResponse"] + | components["schemas"]["signInNotAllowedResponse"] + | components["schemas"]["fieldErrorResponse"] + | components["schemas"]["wrongCredentialsResponse"] + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + signUp: { + parameters: { + query?: never; + header?: { + /** @example emailpassword */ + rid?: components["parameters"]["emailPasswordRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + formFields: components["schemas"]["formFields"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Sign up Response */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | components["schemas"]["signupResponse"] + | components["schemas"]["signUpNotAllowedResponse"] + | components["schemas"]["fieldErrorResponse"] + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + emailExistsDepr: { + parameters: { + query: { + email: components["parameters"]["email"]; + }; + header?: { + /** @example emailpassword */ + rid?: components["parameters"]["emailPasswordRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if an email exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + emailExists: { + parameters: { + query: { + email: components["parameters"]["email"]; + }; + header?: { + /** @example emailpassword */ + rid?: components["parameters"]["emailPasswordRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if an email exists */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + exists?: components["schemas"]["exists"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordResetToken: { + parameters: { + query?: never; + header?: { + /** @example emailpassword */ + rid?: components["parameters"]["emailPasswordRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + formFields?: components["schemas"]["formFields"]; + }; + }; + }; + responses: { + /** @description Generate a new reset password token for this user */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | components["schemas"]["passwordResetTokenResponse"] + | components["schemas"]["passwordResetNotAllowedResponse"] + | components["schemas"]["fieldErrorResponse"] + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + passwordReset: { + parameters: { + query?: never; + header?: { + /** @example emailpassword */ + rid?: components["parameters"]["emailPasswordRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + method?: components["schemas"]["method"]; + formFields?: components["schemas"]["formFields"]; + token?: components["schemas"]["token"]; + }; + }; + }; + responses: { + /** @description Reset a password using password reset token */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | components["schemas"]["passwordResetResponse"] + | components["schemas"]["passwordResetErrorResponse"] + | components["schemas"]["fieldErrorResponse"] + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + signInUp: { + parameters: { + query?: never; + header?: { + /** @example thirdparty */ + rid?: components["parameters"]["thirdPartyRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": + | { + thirdPartyId: components["schemas"]["thirdPartyId"]; + clientType?: components["schemas"]["clientType"]; + redirectURIInfo: { + redirectURIOnProviderDashboard: components["schemas"]["redirectURI"]; + /** @example { + * "code": "neqmpdsfuqe141m5lk437867masdf", + * "state": "ljayfgqewertbh13245njw0" + * } */ + redirectURIQueryParams: Record; + /** @example abcd1234 */ + pkceCodeVerifier?: string; + }; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + } + | { + thirdPartyId: components["schemas"]["thirdPartyId"]; + clientType?: components["schemas"]["clientType"]; + oAuthTokens: components["schemas"]["oAuthTokens"]; + /** @example false */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Signin/up a user */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | components["schemas"]["signinupResponse"] + | components["schemas"]["signinupErrorResponse"] + | components["schemas"]["generalErrorResponse"]; + }; + }; + 403: components["responses"]["403-factor-setup"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + authorisationUrl: { + parameters: { + query: { + thirdPartyId: components["schemas"]["thirdPartyId"]; + redirectURIOnProviderDashboard: components["schemas"]["redirectURI"]; + clientType?: components["schemas"]["clientType"]; + }; + header?: { + /** @example thirdparty */ + rid?: components["parameters"]["thirdPartyRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Get the OAuth authorisation URL */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example https://providerdomain.com/authorize?client_id=..&scope=..&access_type=.. */ + urlWithQueryParams?: string; + /** @example abcd1234 */ + pkceCodeVerifier?: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + loginmethods: { + parameters: { + query?: { + clientType?: components["schemas"]["clientType"]; + }; + header?: { + /** @example multitenancy */ + rid?: components["parameters"]["multitenancyRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Get enabled login methods */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + emailPassword: { + /** @example true */ + enabled: boolean; + }; + thirdParty: { + /** @example true */ + enabled: boolean; + providers: { + id: components["schemas"]["thirdPartyId"]; + /** @example Google */ + name: string; + }[]; + }; + passwordless: { + /** @example true */ + enabled: boolean; + }; + firstFactors: string[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + thirdPartyCallbackApple: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/x-www-form-urlencoded": { + /** @description The Authorization code which will be exchanged for an access token */ + code?: string; + /** @description A unique string used to mitigate CSRF attacks */ + state?: string; + }; + }; + }; + responses: { + /** @description Redirects the user to the client's app. */ + 303: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + verifyEmailToken: { + parameters: { + query?: never; + header?: { + /** @example emailverification */ + rid?: components["parameters"]["emailVerificationRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Send email verification email */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @enum {string} */ + status: "OK" | "EMAIL_ALREADY_VERIFIED_ERROR"; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + verifyEmail: { + parameters: { + query?: never; + header?: { + /** @example emailverification */ + rid?: components["parameters"]["emailVerificationRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + method?: components["schemas"]["method"]; + token?: components["schemas"]["token"]; + }; + }; + }; + responses: { + /** @description Verify an email */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @enum {string} */ + status: "OK" | "EMAIL_VERIFICATION_INVALID_TOKEN_ERROR"; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + getVerifyEmail: { + parameters: { + query?: never; + header?: { + /** @example emailverification */ + rid?: components["parameters"]["emailVerificationRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Checks if an email is verified and adds this information into the access token payload as well */ + 200: { + headers: { + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "Set-Cookie"?: string; + /** @description Sent in cookie-based sessions if the access token payload is updated */ + "st-access-token"?: components["schemas"]["token"]; + /** @description Sent if enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + /** @description Sent if the access token payload is updated */ + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example true */ + isVerified?: boolean; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + getJWKS: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieve JWKs for JWT verification */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + keys?: { + /** + * @description The algorithm to use when creating the JWT. + * @enum {string} + */ + alg?: "RS256"; + /** @example RSA */ + kty?: string; + /** @example sig */ + use?: string; + /** @description Unique identifier for the JWK */ + kid?: string; + /** @description Modulus for the key */ + n?: string; + /** @description Exponent for the key */ + e?: string; + }[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + getOpenIdDiscoveryConfiguration: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieve OpenID configuration */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** + * @description URL using the https scheme with no query or fragment component that the OP asserts as its Issuer Identifier (https://openid.net/specs/openid-connect-discovery-1_0.html section 3) + * @example https://api.example.com/auth + */ + issuer?: string; + /** + * @description URL for fetching a list JsonWebKey, used for JWT signature verification. Refer to /jwt/jwks.json API in the JWT recipe for JWK details + * @example https://api.example.com/auth/jwt/jwks.json + */ + jwks_uri?: string; + /** + * @description URL of the authorization endpoint + * @example https://api.example.com/auth/oauth/authorize + */ + authorization_endpoint?: string; + /** + * @description URL of the token endpoint + * @example https://api.example.com/auth/oauth/token + */ + token_endpoint?: string; + /** + * @description URL of the userinfo endpoint + * @example https://api.example.com/auth/oauth/userinfo + */ + userinfo_endpoint?: string; + /** + * @description URL of the token revocation endpoint + * @example https://api.example.com/auth/oauth/revoke + */ + revocation_endpoint?: string; + /** + * @description URL of the token introspection endpoint + * @example https://api.example.com/auth/oauth/introspect + */ + token_introspection_endpoint?: string; + /** + * @description URL of the end session endpoint + * @example https://api.example.com/auth/oauth/end_session + */ + end_session_endpoint?: string; + subject_types_supported?: "public"[]; + id_token_signing_alg_values_supported?: "RS256"[]; + response_types_supported?: ("code" | "id_token" | "id_token token")[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthLoginGET: { + parameters: { + query: { + loginChallenge: string; + }; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The next url in the login flow */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** + * @description The URL to redirect the user to + * @example https://client.com/callback?code=asdf1234567890&status=asdf1234 + */ + frontendRedirectTo?: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthAuthGET: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A general error response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["generalErrorResponse"]; + }; + }; + /** @description Redirects the user to the login page or back to the client app */ + 302: { + headers: { + Location?: string; + [name: string]: unknown; + }; + content?: never; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthTokenPOST: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Issued tokens */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @description The access token issued by the authorization server. */ + access_token?: string; + /** @description The lifetime in seconds of the access token (integer). For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated. */ + expires_in: number; + /** @description To retrieve a refresh token request the id_token scope. */ + id_token?: string; + /** @description The refresh token, which can be used to obtain new access tokens. To retrieve it add the scope "offline" to your access token request. */ + refresh_token?: string; + /** @description The scope of the access token */ + scope: string; + /** @description The type of the token issued */ + token_type: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthUserInfoGET: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieved user information */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + sub: components["schemas"]["userId"]; + /** + * @description The email of the user + * @example johndoe@gmail.com + */ + email?: string; + /** + * @description Whether the email is verified + * @example true + */ + email_verified?: boolean; + emails?: string[]; + /** + * @description The phoneNumber of the user + * @example 0036701234567 + */ + phoneNumber?: string; + /** + * @description Whether the phoneNumber is verified + * @example true + */ + phoneNumber_verified?: boolean; + phoneNumbers?: string[]; + roles?: string[]; + permissions?: string[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + /** @description The access token is expired, revoked or malformed */ + 401: { + headers: { + "WWW-Authenticate"?: string; + [name: string]: unknown; + }; + content: { + "application/json": { + /** @example Invalid or expired OAuth2 access token */ + message?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthRevokePOST: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + token: string; + /** @example st-cl-test-client */ + client_id?: string; + /** @example superSecret */ + client_secret?: string; + }; + "x-www-form-urlencoded": { + token: string; + /** @example st-cl-test-client */ + client_id?: string; + /** @example superSecret */ + client_secret?: string; + }; + }; + }; + responses: { + /** @description Revoked the access/refresh token */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthIntrospectPOST: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + token: string; + }; + "application/x-www-form-urlencoded": { + token: string; + }; + }; + }; + responses: { + /** @description Information about the token */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** + * @description Whether the token is active or not + * @example true + */ + active: boolean; + /** + * @description The type of the token + * @example Bearer + */ + token_type?: string; + /** + * @description The use of the token + * @example access_token + */ + token_use?: string; + sub?: components["schemas"]["userId"]; + /** + * @description The email of the user + * @example johndoe@gmail.com + */ + email?: string; + /** + * @description Whether the email is verified + * @example true + */ + email_verified?: boolean; + emails?: string[]; + /** + * @description The phoneNumber of the user + * @example 0036701234567 + */ + phoneNumber?: string; + /** + * @description Whether the phoneNumber is verified + * @example true + */ + phoneNumber_verified?: boolean; + phoneNumbers?: string[]; + roles?: string[]; + permissions?: string[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthEndSessionGET: { + parameters: { + query?: { + id_token_hint?: string; + client_id?: string; + post_logout_redirect_uri?: string; + }; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A general error response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["generalErrorResponse"]; + }; + }; + /** @description Redirects the user to the logout page or back to the client app */ + 302: { + headers: { + Location?: string; + [name: string]: unknown; + }; + content?: never; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthEndSessionPOST: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + id_token_hint?: string; + /** @example st-cl-example-client */ + client_id?: string; + /** @example https://client.example.com/logoutCallback */ + post_logout_redirect_uri?: string; + }; + "application/x-www-form-urlencoded": { + id_token_hint?: string; + /** @example st-cl-example-client */ + client_id?: string; + /** @example https://client.example.com/logoutCallback */ + post_logout_redirect_uri?: string; + }; + }; + }; + responses: { + /** @description A general error response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["generalErrorResponse"]; + }; + }; + /** @description Redirects the user to the logout page or back to the client app */ + 302: { + headers: { + Location?: string; + [name: string]: unknown; + }; + content?: never; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthLoginInfoGET: { + parameters: { + query: { + loginChallenge: string; + }; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Information about the current login flow */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @description Information about the current login flow */ + info: { + /** @description The ID of the client. */ + clientId: string; + /** @description The name of the client. */ + clientName: string; + /** @description The URI of the client's terms of service. */ + tosUri?: string; + /** @description The URI of the client's privacy policy. */ + policyUri?: string; + /** @description The URI of the client's logo. */ + logoUri?: string; + /** @description The URI of the client we can link to on the login page */ + clientUri?: string; + }; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + oauthLogoutPOST: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + logoutChallenge: string; + }; + "x-www-form-urlencoded": { + logoutChallenge: string; + }; + }; + }; + responses: { + /** @description Accepts the logout request specified by the challenge and gets where the user should be redirected to */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** + * @description The URL to redirect the user to + * @example https://auth.example.com/auth/oauth/logout?logoutChallenge=1234567890 + */ + frontendRedirectTo?: string; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 400: components["responses"]["400-oauth-error"]; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + exampleAppAPI: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description The session passed verification and went through the application code */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The session doesn't exists or if it needs to be refreshed */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * @description unauthorised or try refresh token + * @example try refresh token + */ + message?: string; + }; + }; + }; + /** @description The session exists, but didn't pass a claim validator */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** @example invalid claim */ + message?: string; + claimValidationErrors?: { + /** @example st-ev */ + id?: string; + /** @example { + * "message": "value does not exist", + * "expectedValue": "val", + * "actualValue": "claimVal" + * } */ + reason?: Record; + }[]; + }; + }; + }; + }; + }; + webauthnRegisterOptions: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": + | { + email: components["schemas"]["email"]; + /** @example John Doe */ + displayName?: string; + } + | { + /** @example abc123... */ + recoverAccountToken: string; + }; + }; + }; + responses: { + /** @description WebAuthn registration options */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example opt_123... */ + webauthnGeneratedOptionsId: string; + /** @example 2024-03-20T10:00:00Z */ + createdAt: string; + /** @example 2024-03-20T10:05:00Z */ + expiresAt: string; + rp: { + /** @example example.com */ + id: string; + /** @example Example Site */ + name: string; + }; + user: { + /** @example user_123... */ + id: string; + /** @example john@example.com */ + name: string; + /** @example John Doe */ + displayName: string; + }; + /** @example base64challenge... */ + challenge: string; + /** @example 300000 */ + timeout: number; + excludeCredentials: { + id: string; + /** @enum {string} */ + type: "public-key"; + transports: ("ble" | "hybrid" | "internal" | "nfc" | "usb")[]; + }[]; + /** @enum {string} */ + attestation: "none" | "indirect" | "direct" | "enterprise"; + pubKeyCredParams: { + /** @example -7 */ + alg: number; + /** @enum {string} */ + type: "public-key"; + }[]; + authenticatorSelection: { + requireResidentKey: boolean; + /** @enum {string} */ + residentKey: "required" | "preferred" | "discouraged"; + /** @enum {string} */ + userVerification: "required" | "preferred" | "discouraged"; + }; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "INVALID_OPTIONS_ERROR" | "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR"; + } + | { + /** @enum {string} */ + status: "INVALID_EMAIL_ERROR"; + /** @example Invalid email */ + err?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnSignInOptions: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description WebAuthn sign in options */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example opt_123... */ + webauthnGeneratedOptionsId?: string; + /** @example 2024-03-20T10:00:00Z */ + createdAt?: string; + /** @example 2024-03-20T10:05:00Z */ + expiresAt?: string; + /** @example example.com */ + rpId?: string; + /** @example base64challenge... */ + challenge?: string; + /** @example 300000 */ + timeout?: number; + /** @enum {string} */ + userVerification?: "required" | "preferred" | "discouraged"; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "INVALID_OPTIONS_ERROR"; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnSignUp: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example opt_123... */ + webauthnGeneratedOptionsId: string; + credential: components["schemas"]["registrationPayload"]; + /** @example true */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Sign up response */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "INVALID_CREDENTIALS_ERROR" | "EMAIL_ALREADY_EXISTS_ERROR"; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnSignIn: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example opt_123... */ + webauthnGeneratedOptionsId: string; + credential: components["schemas"]["authenticationPayload"]; + /** @example true */ + shouldTryLinkingWithSessionUser?: boolean; + }; + }; + }; + responses: { + /** @description Sign in response */ + 200: { + headers: { + /** @description In cookie-based sessions */ + "Set-Cookie"?: string; + /** @description In header-based sessions */ + "st-access-token"?: components["schemas"]["token"]; + /** @description In header-based sessions */ + "st-refresh-token"?: components["schemas"]["token"]; + /** @description If enabled by the user */ + "anti-csrf"?: components["schemas"]["token"]; + "front-token"?: components["schemas"]["token"]; + "Access-Control-Expose-Headers"?: string; + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "INVALID_CREDENTIALS_ERROR"; + } + | { + /** @enum {string} */ + status: "SIGN_IN_NOT_ALLOWED"; + /** @example Sign in not allowed */ + reason?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnGenerateRecoverAccountToken: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + email: components["schemas"]["email"]; + }; + }; + }; + responses: { + /** @description Recovery token generation response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "RECOVER_ACCOUNT_NOT_ALLOWED"; + /** @example Recover account not allowed */ + reason?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnRecoverAccount: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example abc123... */ + token: string; + /** @example opt_123... */ + webauthnGeneratedOptionsId: string; + credential: components["schemas"]["registrationPayload"]; + }; + }; + }; + responses: { + /** @description Account recovery response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + user?: components["schemas"]["user"]; + email?: components["schemas"]["email"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: + | "INVALID_CREDENTIALS_ERROR" + | "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR" + | "OPTIONS_NOT_FOUND_ERROR" + | "INVALID_OPTIONS_ERROR"; + } + | { + /** @enum {string} */ + status: "INVALID_AUTHENTICATOR_ERROR"; + /** @example Invalid authenticator */ + reason?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnRegisterCredential: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example opt_123... */ + webauthnGeneratedOptionsId: string; + /** @example user_123... */ + recipeUserId: string; + credential: components["schemas"]["registrationPayload"]; + }; + }; + }; + responses: { + /** @description Credential registration response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "INVALID_CREDENTIALS_ERROR" | "OPTIONS_NOT_FOUND_ERROR" | "INVALID_OPTIONS_ERROR"; + } + | { + /** @enum {string} */ + status: "REGISTER_CREDENTIAL_NOT_ALLOWED" | "INVALID_AUTHENTICATOR_ERROR"; + /** @example Register credential not allowed */ + reason?: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnRemoveCredential: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: { + content: { + "application/json": { + /** @example cred_123... */ + webauthnCredentialId: string; + }; + }; + }; + responses: { + /** @description Credential removal response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + } + | components["schemas"]["generalErrorResponse"] + | { + /** @enum {string} */ + status: "CREDENTIAL_NOT_FOUND_ERROR"; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnListCredentials: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + /** @description This will only be here if enabled by the user. */ + "anti-csrf"?: components["parameters"]["anti-csrf"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Credential list response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + credentials?: { + /** @example cred_123... */ + webauthnCredentialId: string; + /** @example https://example.com */ + relyingPartyId: string; + /** @example user_123... */ + recipeUserId: string; + /** @example 1638433545183 */ + createdAt: number; + }[]; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnEmailExists: { + parameters: { + query: { + email: components["parameters"]["email"]; + }; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Email existence check response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + status: components["schemas"]["statusOK"]; + /** @example true */ + exists?: boolean; + } + | components["schemas"]["generalErrorResponse"]; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnResetToken: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + email: string; + }; + }; + }; + responses: { + /** @description Reset token response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @enum {string} */ + status: "OK"; + } + | { + /** @enum {string} */ + status: "GENERAL_ERROR"; + message: string; + } + | { + /** @enum {string} */ + status: "RECOVER_ACCOUNT_NOT_ALLOWED"; + reason: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; + webauthnReset: { + parameters: { + query?: never; + header?: { + /** @example webauthn */ + rid?: components["parameters"]["webauthnRid"]; + }; + path: { + /** @description Its value depends on the apiBasePath set by the user */ + apiBasePath: components["parameters"]["apiBasePath"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + token: string; + webauthnGeneratedOptionsId: string; + credential: components["schemas"]["registrationPayload"]; + }; + }; + }; + responses: { + /** @description WebAuthn account reset response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": + | { + /** @enum {string} */ + status: "OK"; + user: components["schemas"]["user"]; + email: string; + } + | { + /** @enum {string} */ + status: "GENERAL_ERROR"; + message: string; + } + | { + /** @enum {string} */ + status: + | "RECOVER_ACCOUNT_TOKEN_INVALID_ERROR" + | "INVALID_CREDENTIALS_ERROR" + | "OPTIONS_NOT_FOUND_ERROR" + | "INVALID_OPTIONS_ERROR"; + } + | { + /** @enum {string} */ + status: "INVALID_AUTHENTICATOR_ERROR"; + reason: string; + }; + }; + }; + 404: components["responses"]["404"]; + 500: components["responses"]["500"]; + }; + }; +}