paths: "/?ctrl=clientManagementCtl&api=getChallenge&ver=v1": post: operationId: getMobileLoginChallenge summary: Get mobile login challenge description: | Conceptual path: `POST /mobile/auth/challenge`. Returns a short-lived server-signed challenge JWT used by the mobile app to bind device attestation and login confirmation to a fresh server challenge. The request includes `phone_number` so the challenge can carry the password salt needed by the mobile SDK to build the signed login proof. Unknown phone numbers receive a deterministic fake salt to avoid account enumeration. tags: [Mobile Auth] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/GetLoginChallengeRequest" example: platform: "ios" app_version: "1.0.0" phone_number: "+66812345678" responses: "200": description: Challenge token generated. content: application/json: schema: $ref: "../components.yaml#/components/schemas/GetLoginChallengeResponse" example: challenge_token: "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9..." "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=login&ver=v1": post: operationId: mobileLogin summary: Login with signed password proof and device proof description: | Conceptual path: `POST /mobile/auth/login`. Verifies the signed `confirm_jwt`, password proof, challenge token, and mobile device proof. `phone_number` and `password` are not top-level request fields; the signed JWT carries `phone_number` and `password_proof`. Login mode is inferred from `confirm_jwt.tracking_id`: non-empty means new-device registration, empty or absent means registered-device login. On success, creates a pending session, binds it to a device, and sends email OTP. tags: [Mobile Auth] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/LoginRequest" examples: registrationIOS: summary: First login on iOS value: platform: "ios" challenge_token: "" jwt_public_key: kty: "OKP" crv: "Ed25519" x: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" confirm_jwt: "" attestation: type: "apple_app_attest" platform_key_id: "apple-app-attest-key-id" attestation_object: "base64-attestation-object" registeredAndroid: summary: Later login on Android registered device value: platform: "android" challenge_token: "" device_id: "64f1a2b3c4d5e6f7a8b9c011" confirm_jwt: "" play_integrity_token: "" responses: "200": description: Credentials accepted; OTP has been sent. content: application/json: schema: $ref: "../components.yaml#/components/schemas/LoginResponse" example: session_id: "6650f0a2e1b2c3d4e5f60718" device_id: "64f1a2b3c4d5e6f7a8b9c011" user_id: "64f1a2b3c4d5e6f7a8b9c012" tracking_id: "registration-tracking-id" otp_sent_to: "us**@example.com" otp_remaining_time: 1717998600 "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=sendOTP&ver=v1": post: operationId: sendMobileOTP summary: Resend email OTP description: | Conceptual path: `POST /mobile/auth/otp/send`. Resends OTP for the mobile session carried by the `POST_LOGIN` Authorization JWT. Subject to resend limit policy. tags: [Mobile Auth] security: - mobileBearerAuth: [] requestBody: required: false content: application/json: schema: $ref: "../components.yaml#/components/schemas/SendOTPRequest" example: {} responses: "200": description: OTP resent. content: application/json: schema: $ref: "../components.yaml#/components/schemas/SendOTPResponse" example: otp_sent_to: "us**@example.com" resend_available_in: 1717998600 remaining_resends: 4 "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=verifyOTP&ver=v1": post: operationId: verifyMobileOTP summary: Verify email OTP description: | Conceptual path: `POST /mobile/auth/otp/verify`. Verifies the six-digit OTP for the mobile session carried by the `POST_LOGIN` Authorization JWT. On success, returns whether the user already has a passcode. tags: [Mobile Auth] security: - mobileBearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/VerifyOTPRequest" example: otp: "123456" responses: "200": description: OTP accepted. content: application/json: schema: $ref: "../components.yaml#/components/schemas/VerifyOTPResponse" example: next_step: "verify_passcode" "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=createPasscode&ver=v1": post: operationId: createMobilePasscode summary: Create account passcode description: | Conceptual path: `POST /mobile/auth/passcode/create`. Creates the user's six-digit passcode. The `POST_LOGIN` Authorization JWT is still required for authentication, and `session_id` in the request body identifies the pending mobile session. On success, returns the next mobile login step. tags: [Mobile Auth] security: - mobileBearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/CreatePasscodeRequest" example: session_id: "6650f0a2e1b2c3d4e5f60718" passcode: "213456" confirm_passcode: "213456" responses: "200": description: Passcode created. content: application/json: schema: $ref: "../components.yaml#/components/schemas/CreatePasscodeResponse" example: next_step: "enable_biometric" "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=verifyPasscode&ver=v1": post: operationId: verifyMobilePasscode summary: Verify passcode on trusted device description: | Conceptual path: `POST /mobile/auth/passcode/verify`. Verifies the user's six-digit passcode. The `POST_LOGIN` Authorization JWT is still required for authentication, and `session_id` in the request body identifies the pending mobile session. On success, returns the next mobile login step. tags: [Mobile Auth] security: - mobileBearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/VerifyPasscodeRequest" example: session_id: "6650f0a2e1b2c3d4e5f60718" device_id: "64f1a2b3c4d5e6f7a8b9c011" passcode: "213456" responses: "200": description: Passcode accepted. content: application/json: schema: $ref: "../components.yaml#/components/schemas/VerifyPasscodeResponse" example: next_step: "verify_biometric" "400": $ref: "../components.yaml#/components/responses/Failure" "/?ctrl=clientManagementCtl&api=enableBiometric&ver=v1": post: operationId: enableMobileBiometric summary: Enable biometric authentication description: | Conceptual path: `POST /mobile/auth/biometric/enable`. Enables biometric authentication on the current trusted device for the mobile session carried by the `POST_LOGIN` Authorization JWT. tags: [Mobile Auth] security: - mobileBearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "../components.yaml#/components/schemas/EnableBiometricRequest" example: {} responses: "200": description: Biometric authentication enabled. content: application/json: schema: $ref: "../components.yaml#/components/schemas/EnableBiometricResponse" example: {} "400": $ref: "../components.yaml#/components/responses/Failure"