mirror of
https://github.com/logto-io/logto.git
synced 2025-04-07 23:01:25 -05:00
feat(core): add experience APIs openapi docs (#6436)
* feat(core): add experience APIs openapi docs add experience APIs openapi docs * fix(core): adjust the format adjust the format * chore: update experience API description update experience API description * fix(core): fix integration tests fix integration tests * chore(core): add devFeature tag in openapi doc add devFeature tag in openapi doc * fix(core): fix the integration test remove the redundent path paramter def
This commit is contained in:
parent
976558af9c
commit
db42279ed4
22 changed files with 1083 additions and 34 deletions
|
@ -368,7 +368,6 @@ export default class ExperienceInteraction {
|
|||
/**
|
||||
* Submit the current interaction result to the OIDC provider and clear the interaction data
|
||||
*
|
||||
* @throws {RequestError} with 404 if the interaction event is not set
|
||||
* @throws {RequestError} with 404 if the user is not identified
|
||||
* @throws {RequestError} with 403 if the mfa verification is required but not verified
|
||||
* @throws {RequestError} with 422 if the profile data is conflicting with the current user account
|
||||
|
@ -380,12 +379,6 @@ export default class ExperienceInteraction {
|
|||
queries: { users: userQueries },
|
||||
} = this.tenant;
|
||||
|
||||
// Initiated
|
||||
assertThat(
|
||||
this.interactionEvent,
|
||||
new RequestError({ code: 'session.interaction_not_found', status: 404 })
|
||||
);
|
||||
|
||||
// Identified
|
||||
const user = await this.getIdentifiedUser();
|
||||
|
||||
|
|
|
@ -95,7 +95,6 @@ export class NewPasswordIdentityVerification
|
|||
* - Validate the password against the password policy
|
||||
*
|
||||
* @throws {RequestError} with status 422 if the identifier is in use by another user
|
||||
* @throws {RequestError} with status 422 if the password is not provided
|
||||
* @throws {RequestError} with status 422 if the password does not meet the password policy
|
||||
*/
|
||||
async verify(password: string) {
|
||||
|
@ -103,11 +102,6 @@ export class NewPasswordIdentityVerification
|
|||
const identifierProfile = interactionIdentifierToUserProfile(identifier);
|
||||
await this.profileValidator.guardProfileUniquenessAcrossUsers(identifierProfile);
|
||||
|
||||
assertThat(
|
||||
password,
|
||||
new RequestError({ code: 'user.password_required_in_profile', status: 422 })
|
||||
);
|
||||
|
||||
const passwordPolicy = await this.signInExperienceValidator.getPasswordPolicy();
|
||||
const passwordValidator = new PasswordValidator(passwordPolicy);
|
||||
await passwordValidator.validatePassword(password, identifierProfile);
|
||||
|
|
124
packages/core/src/routes/experience/experience.openapi.json
Normal file
124
packages/core/src/routes/experience/experience.openapi.json
Normal file
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"tags": [
|
||||
{
|
||||
"name": "Experience",
|
||||
"description": "The Experience endpoints allow end-users to interact with Logto for identity verification and profile completion."
|
||||
},
|
||||
{ "name": "Dev feature" }
|
||||
],
|
||||
"paths": {
|
||||
"/api/experience": {
|
||||
"put": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Init a new experience interaction",
|
||||
"description": "Init a new experience interaction with the given interaction type. Any existing experience interaction data will be cleared.",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "A new experience interaction has been successfully initiated."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/interaction-event": {
|
||||
"put": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Update current experience interaction event",
|
||||
"description": "Update the current experience interaction event to the given event type. This API is used to switch the interaction event between `SignIn` and `Register`, while keeping all the verification records data.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"interactionEvent": {
|
||||
"description": "The type of the interaction event. Only `SignIn` and `Register` are supported."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "The interaction event has been successfully updated."
|
||||
},
|
||||
"400": {
|
||||
"description": "The interaction event is invalid or cannot be updated. Only `SignIn` and `Register` are interchangeable. If the current interaction event is `ForgotPassword`, it cannot be updated."
|
||||
},
|
||||
"403": {
|
||||
"description": "The given interaction event is not enabled in the sign-in experience settings."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/identification": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Identify the user within the current experience interaction using the provided verification data",
|
||||
"description": "This API identifies the user based on the verificationId within the current experience interaction: <br/>- `SignIn` and `ForgotPassword` interactions: Verifies the user's identity using the provided `verificationId`. <br/>- `Register` interaction: Creates a new user account using the profile data from the current interaction. If a verificationId is provided, the profile data will first be updated with the verification record before creating the account. If not, the account is created directly from the stored profile data.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The ID of the verification record used to identify the user. <br/>- `SignIn` and `ForgotPassword` interactions: Required to verify the user's identity. <br/>- `Register` interaction: Optional. If provided, it updates the profile data with the verification record before account creation. If omitted, the account is created using existing profile data in the current interaction."
|
||||
},
|
||||
"linkSocialIdentity": {
|
||||
"description": "Applies to the SignIn interaction only, and is used when a SocialVerification type verificationId is provided. <br/>- If `true`, the user is identified using the verified email or phone number from the social identity provider, and the social identity is linked to the user's account. <br/>- If `false` or not provided, the API identifies the user solely through the social identity. <br/> This parameters is used for linking a non-existing social identity to a related user account that can be identified through the verified email or phone number."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "`Register` interaction: The user account has been successfully created and identified."
|
||||
},
|
||||
"204": {
|
||||
"description": "`SignIn` and `ForgotPassword` interactions: The user has been successfully identified."
|
||||
},
|
||||
"400": {
|
||||
"description": "The provided verificationId is invalid, not verified, or cannot be used to identify the user. <br/>- `session.verification_failed:` The verification is not verified or can not be used to identify the user. <br/>- `guard.invalid_target:` The `verificationId` is missing, but required for the `SignIn` and `ForgotPassword` interactions."
|
||||
},
|
||||
"401": {
|
||||
"description": "The user is suspended or banned from the service. (SignIn and ForgotPassword only)"
|
||||
},
|
||||
"403": {
|
||||
"description": "The `SignIn` or `Register` interaction is disabled in the experience settings."
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/>- `session.verification_session_not_found:` The verification record is not found. <br/>- `user.user_not_exist:` The user account is not found (SignIn and ForgotPassword only). "
|
||||
},
|
||||
"409": {
|
||||
"description": "The interaction has already been identified with a different user account."
|
||||
},
|
||||
"422": {
|
||||
"description": "The user account cannot be created due to validation errors, check error message for more details (Register only). <br/>- `user.<identifier>_already_in_use:` The given identifier is already in use by another user account. <br/>- `user.missing_profile:` Sign-in experience required user identifier or profile data is missing. (Register only)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/submit": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Submit experience interaction",
|
||||
"description": "Submit the current interaction. <br/>- Submit the verified user identity to the OIDC provider for further authentication (SignIn and Register). <br/>- Update the user's profile data if any (SignIn and Register). <br/>- Reset the password and clear all the interaction records (ForgotPassword).",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The interaction has been successfully submitted."
|
||||
},
|
||||
"403": {
|
||||
"description": "Multi-Factor Authentication (MFA) is enabled for the user but has not been verified."
|
||||
},
|
||||
"404": {
|
||||
"description": "The user has not been identified. "
|
||||
},
|
||||
"422": {
|
||||
"description": "The user profile can not been processed, check error message for more details. <br/>- The profile data is invalid or conflicts with existing user data. <br/>- Required profile data is missing. <br/>- The profile data is already in use by another user account."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ export default function experienceApiRoutes<T extends AnonymousRouter>(
|
|||
body: z.object({
|
||||
interactionEvent: z.nativeEnum(InteractionEvent),
|
||||
}),
|
||||
status: [204, 403],
|
||||
status: [204],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { interactionEvent } = ctx.guard.body;
|
||||
|
|
142
packages/core/src/routes/experience/profile-routes.openapi.json
Normal file
142
packages/core/src/routes/experience/profile-routes.openapi.json
Normal file
|
@ -0,0 +1,142 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/profile": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Fulfill user profile data",
|
||||
"description": "Adds user profile data to the current experience interaction. <br/>- For `Register`: The profile data provided before the identification request will be used to create a new user account. <br/>- For `SignIn` and `Register`: The profile data provided after the user is identified will be used to update the user's profile when the interaction is submitted. <br/>- `ForgotPassword`: Not supported.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "The type of profile data to add. `email`, `phone`, `username`, `password`, etc."
|
||||
},
|
||||
"value": {
|
||||
"description": "The plain text value of the profile data. Only supported for profile data types that does not require verification, such as `username` and `password`."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The ID of the verification record used to verify the profile data. Required for profile data types that require verification, such as `email`, `phone` and `social`."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "The profile data has been successfully added to the current experience interaction."
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid request. <br/> - `session.not_supported_for_forgot_password:` This API can not be used in the `ForgotPassword` interaction. <br/>- `session.verification_failed:` The verification record is not verified. "
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/> - `session.identifier_not_found:` (`SignIn` interaction only) The current interaction is not identified yet. All profile data must be associated with a identified user. <br/>- `session.verification_session_not_found:` The verification record is not found."
|
||||
},
|
||||
"403": {
|
||||
"description": "`SignIn` interaction only: Multi-Factor Authentication (MFA) is enabled for the user but has not been verified. The user must verify the MFA before updating the profile data."
|
||||
},
|
||||
"422": {
|
||||
"description": "The user profile can not been processed, check error message for more details. <br/>- The profile data is invalid or conflicts with existing user data. <br/>- The profile data is already in use by another user account."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/profile/password": {
|
||||
"put": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Reset user password",
|
||||
"description": "Update the user's password. (`ForgotPassword` interaction only)",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"password": {
|
||||
"description": "The new password to update. The password must meet the password policy requirements and can not be the same as the current password."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "The password has been successfully updated."
|
||||
},
|
||||
"400": {
|
||||
"description": "The current interaction event is not `ForgotPassword`. The password can only be updated through the `ForgotPassword` interaction."
|
||||
},
|
||||
"404": {
|
||||
"description": "The user has not been identified yet. The user must be identified before updating the password."
|
||||
},
|
||||
"422": {
|
||||
"description": "The password can not be updated due to validation errors, check error message for more details. <br/>- `user.password_policy_violation:` The password does not meet the password policy requirements. <br/>- `user.same_password:` The new password is the same as the current password."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/profile/mfa/mfa-skipped": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Skip Multi-Factor Authentication (MFA) binding flow",
|
||||
"description": "Skip MFA verification binding flow. If the MFA is enabled in the sign-in experience settings and marked as `UserControlled`, the user can skip the MFA verification binding flow by calling this API.",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "The MFA verification has been successfully skipped."
|
||||
},
|
||||
"400": {
|
||||
"description": "Not supported for the current interaction event. The MFA profile API can only be used in the `SignIn` or `Register` interaction."
|
||||
},
|
||||
"403": {
|
||||
"description": "Some MFA factors has already been enabled for the user. The user must verify the MFA before updating the MFA settings."
|
||||
},
|
||||
"404": {
|
||||
"description": "The user has not been identified yet. The `mfa-skipped` configuration must be associated with a identified user."
|
||||
},
|
||||
"422": {
|
||||
"description": "The MFA verification binding is `Mandatory`, user can not skip the MFA verification binding flow."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/profile/mfa": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Bind Multi-Factor Authentication (MFA) verification by verificationId",
|
||||
"description": "Bind new MFA verification to the user profile using the verificationId.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "The type of MFA."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The ID of the MFA verification record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "The MFA verification has been successfully added to the user profile."
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid request. <br/>- `session.verification_failed:` The MFA verification record is invalid or not verified. <br/>- `session.mfa.mfa_factor_not_enabled:` The MFA factor is not enabled in the sign-in experience settings. <br/>- `session.mfa.pending_info_not_found:` The MFA verification record does not have the required information to bind the MFA verification."
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/> - `session.identifier_not_found:` The user has not been identified yet. The MFA verification can only be added to a identified user. <br/>- `session.verification_session_not_found:` The MFA verification record is not found."
|
||||
},
|
||||
"422": {
|
||||
"description": "The MFA verification can not been processed, check error message for more details. <br/>- `user.totp_already_in_use`: A TOTP MFA secret is already in use in the current user profile. <br/>- `session.mfa.backup_code_can_not_be_alone`: The backup code can not be the only MFA factor in the user profile."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/backup-code/generate": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Generate backup codes",
|
||||
"description": "Generate backup codes for the current user. A new BackupCode verification record will be created in the current interaction.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Backup codes have been successfully generated.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"codes": {
|
||||
"description": "The generated backup codes."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the newly created BackupCode verification record. This ID is required when adding the backup codes to the user profile via the Profile API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "The current interaction is not identified yet. All MFA verification records must be associated with a identified user."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/backup-code/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify backup code",
|
||||
"description": "Verify the provided backup code against the user's backup codes. A new BackupCode verification record will be created and marked as verified if the code is correct.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "The backup code to verify."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The backup code has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the BackupCode verification record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/> - `session.identifier_not_found:` The current interaction is not identified yet. All MFA verification records must be associated with a identified user."
|
||||
},
|
||||
"400": {
|
||||
"description": "The provided backup code is invalid."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import { Action } from '@logto/schemas/lib/types/log/interaction.js';
|
|||
import type Router from 'koa-router';
|
||||
import { z } from 'zod';
|
||||
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
import type TenantContext from '#src/tenants/TenantContext.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
|
@ -34,7 +35,10 @@ export default function backupCodeVerificationRoutes<T extends ExperienceInterac
|
|||
async (ctx, next) => {
|
||||
const { experienceInteraction } = ctx;
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({ code: 'session.identifier_not_found', status: 404 })
|
||||
);
|
||||
|
||||
const backupCodeVerificationRecord = BackupCodeVerification.create(
|
||||
libraries,
|
||||
|
@ -80,7 +84,13 @@ export default function backupCodeVerificationRoutes<T extends ExperienceInterac
|
|||
},
|
||||
});
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const backupCodeVerificationRecord = BackupCodeVerification.create(
|
||||
libraries,
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/sso/{connectorId}/authorization-uri": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Get SSO authorization URI",
|
||||
"description": "Create a new EnterpriseSSO verification record and return the authorization URI for the given connector.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"redirectUri": {
|
||||
"description": "The URI to redirect the user after the SSO authorization is completed."
|
||||
},
|
||||
"state": {
|
||||
"description": "The state parameter to pass to the SSO connector."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The SSO authorization URI has been successfully generated.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"authorizationUri": {
|
||||
"description": "The SSO authorization URI."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the newly created EnterpriseSSO verification record. The `verificationId` is required when verifying the SSO authorization response."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "The SSO connector is not found."
|
||||
},
|
||||
"500": {
|
||||
"description": "Connector error. Failed to generate the SSO authorization URI."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/sso/{connectorId}/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify SSO authorization response",
|
||||
"description": "Verify the SSO authorization response data and get the user's profile data from the SSO connector.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The ID of the EnterpriseSSO verification record."
|
||||
},
|
||||
"connectorData": {
|
||||
"description": "Arbitrary data returned by the SSO provider to complete the verification process."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The SSO authorization response has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The current verified EnterpriseSSO verification record ID. This ID is required when identifying the user in the current interaction."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The SSO authorization response is invalid or cannot be verified."
|
||||
},
|
||||
"404": {
|
||||
"description": "The verification record or the SSO connector is not found."
|
||||
},
|
||||
"500": {
|
||||
"description": "Connector error. Failed to verify the SSO authorization response or fetch the user info from the SSO provider."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/sso/connectors": {
|
||||
"get": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Get all the enabled SSO connectors by the given email's domain",
|
||||
"description": "Extract the email domain from the provided email address. Returns all the enabled SSO connectors that match the email domain.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "email",
|
||||
"in": "query",
|
||||
"description": "The email address to find the enabled SSO connectors."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The enabled SSO connectors have been successfully retrieved.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"connectorIds": {
|
||||
"description": "The list of enabled SSO connectorIds. Returns an empty array if no enabled SSO connectors are found."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The email address is invalid, can not extract a valid domain from it."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/new-password-identity": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Create a new password identity for new user registration use",
|
||||
"description": "Create a NewPasswordIdentity verification record for the new user registration use. The verification record includes a unique user identifier and a password that can be used to verify the user's identity.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"password": {
|
||||
"description": "The new user password. (A password digest will be created and stored securely in the verification record.)"
|
||||
},
|
||||
"identifier": {
|
||||
"description": "The unique user identifier. <br/> Currently, only `username` is accepted. For `email` or `phone` registration, a `CodeVerification` record must be created and used to verify the user's email or phone number identifier."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The NewPasswordIdentity verification record has been successfully created.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the newly created NewPasswordIdentity verification record. The `verificationId` is required when creating a new user account via the `Identification` API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unable to process the request. <br/>- `user.username_already_in_use:` The provided username is already in use. <br/>- `password.rejected:` The provided password is rejected by the password policy. Detailed password violation information is included in the response."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/password": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Create and verify a new password verification record",
|
||||
"description": "Generate a new Password verification record, which can be used to identify the user through the `Identification` API.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"password": {
|
||||
"description": "The user password."
|
||||
},
|
||||
"identifier": {
|
||||
"description": "The unique identifier of the user that will be used to identify the user along with the provided password."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The Password verification record has been successfully created and verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the newly created Password verification record. The `verificationId` is required when verifying the user's identity via the `Identification` API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The verification attempts have exceeded the maximum limit."
|
||||
},
|
||||
"401": {
|
||||
"description": "The user is suspended or banned from the service."
|
||||
},
|
||||
"422": {
|
||||
"description": "`session.invalid_credentials:` Either the user is not found or the provided password is incorrect."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ export default function passwordVerificationRoutes<T extends ExperienceInteracti
|
|||
`${experienceRoutes.verification}/password`,
|
||||
koaGuard({
|
||||
body: passwordVerificationPayloadGuard,
|
||||
status: [200, 400, 422],
|
||||
status: [200, 400, 401, 422],
|
||||
response: z.object({
|
||||
verificationId: z.string(),
|
||||
}),
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/social/{connectorId}/authorization-uri": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Get social authorization URI",
|
||||
"description": "Create a new SocialVerification record and return the authorization URI for the given connector.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"redirectUri": {
|
||||
"description": "The URI to redirect the user after the social authorization is completed."
|
||||
},
|
||||
"state": {
|
||||
"description": "The state parameter to pass to the social connector."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The social authorization URI has been successfully generated.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"authorizationUri": {
|
||||
"description": "The social authorization URI."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the newly created SocialVerification record. The `verificationId` is required when verifying the social authorization response."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "The social connector is not found."
|
||||
},
|
||||
"500": {
|
||||
"description": "Connector error. Failed to generate the social authorization URI."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/social/{connectorId}/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify social authorization response",
|
||||
"description": "Verify the social authorization response data and get the user's profile data from the social connector.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The ID of the Social verification record."
|
||||
},
|
||||
"connectorData": {
|
||||
"description": "Arbitrary data returned by the social provider to complete the verification process."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The social authorization response has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the SocialVerification record. This ID is required when identifying the user in the current interaction."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The social authorization response is invalid or cannot be verified."
|
||||
},
|
||||
"404": {
|
||||
"description": "The social connector is not found."
|
||||
},
|
||||
"500": {
|
||||
"description": "Connector error. Failed to verify the social authorization response or fetch the user info from the social provider."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/totp/secret": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Generate TOTP secret for new TOTP binding",
|
||||
"description": "Creates a new TOTP secret for the user to bind a new TOTP verification to their account.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "TOTP secret successfully generated.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"secret": {
|
||||
"description": "The newly generated TOTP secret."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID for the TOTP record. This ID is required to verify the TOTP code."
|
||||
},
|
||||
"secretQrCode": {
|
||||
"description": "A QR code image data URL for the TOTP secret. The user can scan this QR code with their TOTP authenticator app."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/> - `session.identifier_not_found:` The current interaction is not identified yet. All MFA verification records must be associated with a identified user."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/totp/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify TOTP code",
|
||||
"description": "Verifies the provided TOTP code against the user's TOTP secret. If the code is correct, a new TOTP verification record will be created and marked as verified..",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "The TOTP code to be verified."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The verification ID of the newly created TOTP secret. This ID is required to verify a newly created TOTP secret that needs to be bound to the user account. If not provided, the API will create a new TOTP verification record and verify the code against the user's existing TOTP secret."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The TOTP code has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the TOTP verification record. For newly created TOTP secret verification record, this ID is required to bind the TOTP secret to the user account through `Profile` API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid TOTP code."
|
||||
},
|
||||
"404": {
|
||||
"description": "Verification record not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,7 +36,13 @@ export default function totpVerificationRoutes<T extends ExperienceInteractionRo
|
|||
async (ctx, next) => {
|
||||
const { experienceInteraction } = ctx;
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const totpVerification = TotpVerification.create(
|
||||
libraries,
|
||||
|
@ -84,7 +90,13 @@ export default function totpVerificationRoutes<T extends ExperienceInteractionRo
|
|||
},
|
||||
});
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
// Verify new generated secret
|
||||
if (verificationId) {
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/verification-code": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Create and send verification code",
|
||||
"description": "Creates a new `CodeVerification` record and sends the code to the specified identifier. The code verification can be used to verify the user's identity or bind a new identifier to the user's account.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"description": "The identifier (email address or phone number) to send the verification code to."
|
||||
},
|
||||
"interactionEvent": {
|
||||
"description": "The interaction event for which the verification code will be used. Supported values are `SignIn`, `Register`, and `ForgotPassword`. This determines the template for the verification code."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The verification code has been successfully sent.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique ID of the verification record. Required to verify the code."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "An invalid identifier was provided."
|
||||
},
|
||||
"501": {
|
||||
"description": "The connector for sending the verification code is not configured."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/verification-code/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify verification code",
|
||||
"description": "Verifies the provided verification code against the user's identifier. If successful, the verification record is marked as verified.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "The verification code to be verified."
|
||||
},
|
||||
"identifier": {
|
||||
"description": "The identifier (email address or phone number) to verify the code against. Must match the identifier used to send the verification code."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The verification ID of the CodeVerification record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The verification code was successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "he unique ID of the verification record. Required for user identification via the `Identification` API or to bind the identifier to the user's account via the `Profile` API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The verification code is invalid or the maximum number of attempts has been exceeded. Check the error message for details."
|
||||
},
|
||||
"404": {
|
||||
"description": "Verification record not found."
|
||||
},
|
||||
"501": {
|
||||
"description": "The connector for sending the verification code is not configured."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
{
|
||||
"paths": {
|
||||
"/api/experience/verification/web-authn/registration": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Create WebAuthn registration",
|
||||
"description": "Creates a new WebAuthn registration verification record to allow the user to bind a new WebAuthn credential to their account.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "WebAuthn registration successfully created.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"registrationOptions": {
|
||||
"description": "The WebAuthn registration options that the user needs to create a new WebAuthn credential."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID for the WebAuthn registration record. This ID is required to verify the WebAuthn registration challenge."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Entity not found. <br/> - `session.identifier_not_found:` The current interaction is not identified yet. All MFA verification records must be associated with a identified user."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/web-authn/registration/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify WebAuthn registration",
|
||||
"description": "Verifies the WebAuthn registration response against the user's WebAuthn registration challenge. If the response is valid, the WebAuthn registration record will be marked as verified.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"payload": {
|
||||
"description": "The WebAuthn attestation response from the user's WebAuthn credential."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The verification ID of the WebAuthn registration record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The WebAuthn registration has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the WebAuthn registration record. This `verificationId` is required to bind the WebAuthn credential to the user account via the `Profile` API."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid request. <br/> - `session.mfa.pending_info_not_found:` The WebAuthn registration challenge is missing from the current verification record. <br/>- `session.mfa.webauthn_verification_failed:` The WebAuthn attestation response is invalid or cannot be verified."
|
||||
},
|
||||
"404": {
|
||||
"description": "Verification record not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/web-authn/authentication": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Initiate WebAuthn authentication",
|
||||
"description": "Creates a new WebAuthn authentication verification record, allowing the user to authenticate with their WebAuthn credential.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "WebAuthn authentication successfully initiated.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"authenticationOptions": {
|
||||
"description": "Options for the user to authenticate with their WebAuthn credential."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The unique ID for the WebAuthn authentication record, required to verify the WebAuthn authentication challenge."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The user does not have a verified WebAuthn credential."
|
||||
},
|
||||
"404": {
|
||||
"description": "The current interaction is not yet identified. All MFA verification records must be associated with an identified user."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/experience/verification/web-authn/authentication/verify": {
|
||||
"post": {
|
||||
"tags": ["Dev feature"],
|
||||
"summary": "Verify WebAuthn authentication",
|
||||
"description": "Verifies the WebAuthn authentication response against the user's authentication challenge. Upon successful verification, the WebAuthn authentication verification record will be marked as verified.",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"payload": {
|
||||
"description": "The WebAuthn assertion response from the user's WebAuthn credential."
|
||||
},
|
||||
"verificationId": {
|
||||
"description": "The verification ID of the WebAuthn authentication verification record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The WebAuthn authentication has been successfully verified.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"verificationId": {
|
||||
"description": "The unique verification ID of the WebAuthn authentication verification record."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Invalid request. <br/> - `session.mfa.pending_info_not_found:` The WebAuthn authentication challenge is missing in the current verification record. <br/>- `session.mfa.webauthn_verification_failed:` The WebAuthn assertion response is invalid or cannot be verified."
|
||||
},
|
||||
"404": {
|
||||
"description": "Verification record not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,7 +41,13 @@ export default function webAuthnVerificationRoute<T extends ExperienceInteractio
|
|||
async (ctx, next) => {
|
||||
const { experienceInteraction } = ctx;
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const webAuthnVerification = WebAuthnVerification.create(
|
||||
libraries,
|
||||
|
@ -95,7 +101,13 @@ export default function webAuthnVerificationRoute<T extends ExperienceInteractio
|
|||
},
|
||||
});
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const webAuthnVerification = experienceInteraction.getVerificationRecordByTypeAndId(
|
||||
VerificationType.WebAuthn,
|
||||
|
@ -140,7 +152,13 @@ export default function webAuthnVerificationRoute<T extends ExperienceInteractio
|
|||
async (ctx, next) => {
|
||||
const { experienceInteraction } = ctx;
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const webAuthnVerification = WebAuthnVerification.create(
|
||||
libraries,
|
||||
|
@ -193,7 +211,13 @@ export default function webAuthnVerificationRoute<T extends ExperienceInteractio
|
|||
},
|
||||
});
|
||||
|
||||
assertThat(experienceInteraction.identifiedUserId, 'session.identifier_not_found');
|
||||
assertThat(
|
||||
experienceInteraction.identifiedUserId,
|
||||
new RequestError({
|
||||
code: 'session.identifier_not_found',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const webAuthnVerification = experienceInteraction.getVerificationRecordByTypeAndId(
|
||||
VerificationType.WebAuthn,
|
||||
|
|
|
@ -100,7 +100,12 @@ const createRouters = (tenant: TenantContext) => {
|
|||
statusRoutes(anonymousRouter, tenant);
|
||||
authnRoutes(anonymousRouter, tenant);
|
||||
// The swagger.json should contain all API routers.
|
||||
swaggerRoutes(anonymousRouter, [interactionRouter, managementRouter, anonymousRouter]);
|
||||
swaggerRoutes(anonymousRouter, [
|
||||
interactionRouter,
|
||||
managementRouter,
|
||||
anonymousRouter,
|
||||
experienceRouter,
|
||||
]);
|
||||
|
||||
return [experienceRouter, interactionRouter, managementRouter, anonymousRouter];
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ const anonymousPaths = new Set<string>([
|
|||
'authn',
|
||||
'swagger.json',
|
||||
'status',
|
||||
'experience',
|
||||
]);
|
||||
|
||||
const advancedSearchPaths = new Set<string>([
|
||||
|
|
|
@ -122,7 +122,7 @@ export const throwByDifference = (builtCustomRoutes: Set<string>) => {
|
|||
};
|
||||
|
||||
/** Path segments that are treated as namespace prefixes. */
|
||||
const namespacePrefixes = Object.freeze(['jit', '.well-known']);
|
||||
const namespacePrefixes = Object.freeze(['jit', '.well-known', 'experience']);
|
||||
|
||||
const isPathParameter = (segment?: string) =>
|
||||
Boolean(segment && (segment.startsWith(':') || segment.startsWith('{')));
|
||||
|
@ -154,6 +154,7 @@ const throwIfNeeded = (method: OpenAPIV3.HttpMethods, path: string) => {
|
|||
* @see {@link methodToVerb} for the mapping of HTTP methods to verbs.
|
||||
* @see {@link namespacePrefixes} for the list of namespace prefixes.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
export const buildOperationId = (method: OpenAPIV3.HttpMethods, path: string) => {
|
||||
const customOperationId = customRoutes[`${method} ${path}`];
|
||||
|
||||
|
@ -162,7 +163,8 @@ export const buildOperationId = (method: OpenAPIV3.HttpMethods, path: string) =>
|
|||
}
|
||||
|
||||
// Skip interactions APIs as they are going to replaced by the new APIs soon.
|
||||
if (path.startsWith('/interaction')) {
|
||||
// Skip experience APIs as they are not strictly RESTful.
|
||||
if (path.startsWith('/interaction') || path.startsWith('/experience')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,12 +21,12 @@ devFeatureTest.describe('backup code verification APIs', () => {
|
|||
await userApi.cleanUp();
|
||||
});
|
||||
|
||||
it('should throw 400 if the user is not identified', async () => {
|
||||
it('should throw 404 if the user is not identified', async () => {
|
||||
const client = await initExperienceClient();
|
||||
|
||||
await expectRejects(client.verifyBackupCode({ code: '1234' }), {
|
||||
code: 'session.identifier_not_found',
|
||||
status: 400,
|
||||
status: 404,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -27,12 +27,12 @@ devFeatureTest.describe('TOTP verification APIs', () => {
|
|||
});
|
||||
|
||||
describe('Create new TOTP secret', () => {
|
||||
it('should throw 400 if the user is not identified', async () => {
|
||||
it('should throw 404 if the user is not identified', async () => {
|
||||
const client = await initExperienceClient();
|
||||
|
||||
await expectRejects(client.createTotpSecret(), {
|
||||
code: 'session.identifier_not_found',
|
||||
status: 400,
|
||||
status: 404,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -46,12 +46,12 @@ devFeatureTest.describe('TOTP verification APIs', () => {
|
|||
});
|
||||
|
||||
describe('Verify new TOTP secret', () => {
|
||||
it('should throw 400 if the user is not identified', async () => {
|
||||
it('should throw 404 if the user is not identified', async () => {
|
||||
const client = await initExperienceClient();
|
||||
|
||||
await expectRejects(client.verifyTotp({ code: '1234' }), {
|
||||
code: 'session.identifier_not_found',
|
||||
status: 400,
|
||||
status: 404,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -103,12 +103,12 @@ devFeatureTest.describe('TOTP verification APIs', () => {
|
|||
});
|
||||
|
||||
describe('Verify existing TOTP secret', () => {
|
||||
it('should throw 400 if the user is not identified', async () => {
|
||||
it('should throw 404 if the user is not identified', async () => {
|
||||
const client = await initExperienceClient();
|
||||
|
||||
await expectRejects(client.verifyTotp({ code: '1234' }), {
|
||||
code: 'session.identifier_not_found',
|
||||
status: 400,
|
||||
status: 404,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue