Summary
The OTP flow never enforces expiry or one-time use, and the verify endpoint always returns HTTP 200 with { message: "null" } even on failure. This lets a single OTP be reused indefinitely and makes it impossible for clients to distinguish success vs failure from the response.
Impact
- Reusable OTPs weaken authentication and allow repeated logins with the same code.
- Clients cannot reliably handle failures because the endpoint always returns 200, leading to inconsistent UX and potential security gaps.
Steps to Reproduce
- Call
send-otp to generate an OTP.
- Call
verify-otp with the correct OTP — response is 200.
- Call
verify-otp again with the same OTP — response is still 200 and status is recorded as a string in the DB.
- Call
verify-otp with a wrong OTP — response is also 200 with { message: "null" }.
Expected Behavior
- OTPs expire after a short window (e.g., 5–10 minutes) and are single-use.
- Verification returns success (
200) only when valid; expired or incorrect OTPs return 400/401 with a clear error payload.
- OTP documents are cleaned up or marked consumed after verification attempts.
Actual Behavior
- No expiry or consumption; OTP can be reused indefinitely.
- Endpoint always returns
200 with { message: "null" }, even on failure.
Proposed Fix
- Store
expiresAt when generating the OTP and reject if expired.
- On verification, delete or mark the OTP document as consumed; reject subsequent attempts.
- Return distinct status codes/payloads:
200 on success
400/401 on invalid/expired
500 on server errors
- (Optional) Store verification status as a boolean instead of a string for clearer semantics.
Acceptance Criteria
- OTPs cannot be reused after one successful verification.
- Expired or incorrect OTPs return
400/401 with an explanatory message; valid OTPs return 200 with a success message.
- OTP records are removed or flagged as consumed after verification attempts, preventing reuse.
- Tests or manual verification steps documented to confirm the behaviors above.
Summary
The OTP flow never enforces expiry or one-time use, and the verify endpoint always returns HTTP 200 with
{ message: "null" }even on failure. This lets a single OTP be reused indefinitely and makes it impossible for clients to distinguish success vs failure from the response.Impact
Steps to Reproduce
send-otpto generate an OTP.verify-otpwith the correct OTP — response is200.verify-otpagain with the same OTP — response is still200and status is recorded as a string in the DB.verify-otpwith a wrong OTP — response is also200with{ message: "null" }.Expected Behavior
200) only when valid; expired or incorrect OTPs return400/401with a clear error payload.Actual Behavior
200with{ message: "null" }, even on failure.Proposed Fix
expiresAtwhen generating the OTP and reject if expired.200on success400/401on invalid/expired500on server errorsAcceptance Criteria
400/401with an explanatory message; valid OTPs return200with a success message.