Mock Alpha

Multi-step Auth (OTP)

Mock a login flow that requires OTP confirmation before it succeeds — no code changes, four scenarios

Multi-step Auth (OTP)

A common real flow: the app calls POST /login, the backend answers "OTP required", the user types the code, the app calls POST /verify-otp, and only then does login succeed.

Mock Alpha can serve that whole flow today, with match rules and no new feature. What makes it work is one observation:

The second /login request is not the same request as the first. It carries the token that /verify-otp handed out. That difference is what the rules key off.

This mirrors how real login+OTP backends behave — the pre-auth token exists precisely so the server can tell the two calls apart.

The four scenarios

Two endpoints, four scenarios:

EndpointScenarioMatch rulePriorityResponse
POST /loginneed-otpbody.otpToken not_exists1200 { "requiresOtp": true, "otpToken": "..." }
POST /loginsuccessbody.otpToken exists2200 { "accessToken": "..." }
POST /verify-otpotp-okbody.otp eq 1234561200 { "verified": true, "otpToken": "..." }
POST /verify-otpotp-wrong(default scenario)—400 { "error": "Invalid OTP" }

need-otp and success are mutually exclusive by construction: a request either carries otpToken or it does not.

Walkthrough

1. First login — no token yet, so OTP is demanded

curl -X POST https://mock-alpha.aprix.site/api/mock/login \
  -H "X-Api-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "email": "tester@example.com", "password": "hunter2" }'

body.otpToken is absent → need-otp wins:

{ "requiresOtp": true, "otpToken": "pre-auth-abc123" }

2. Verify the code

curl -X POST https://mock-alpha.aprix.site/api/mock/verify-otp \
  -H "X-Api-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "otp": "123456", "otpToken": "pre-auth-abc123" }'

otp equals 123456 → otp-ok. Any other code falls through to the default scenario and gets 400, which is exactly the wrong-code path you want to test.

3. Second login — now it carries the token

curl -X POST https://mock-alpha.aprix.site/api/mock/login \
  -H "X-Api-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "email": "tester@example.com", "password": "hunter2", "otpToken": "pre-auth-abc123" }'

body.otpToken exists → success:

{ "accessToken": "eyJhbGciOi..." }

Echoing request data back

Use response templates so the mock answers with the data it was given instead of a fixed string:

{
  "accessToken": "mock-token-for-{{request.body.email}}",
  "user": { "email": "{{request.body.email}}" }
}

Checking which scenario was served

Every mock response carries the scenario that produced it:

X-Mock-Scenario: need-otp

When the flow does something you did not expect, read that header first — it tells you whether a rule failed to match or the response body itself is wrong.

Gotchas

SituationWhat happens
Client sends X-Mock-Scenario or ?scenario=Match rules are skipped entirely — an explicit key always wins. Remove it while testing the flow.
Request has no Content-Type: application/jsonThe body is never parsed, so every source=body rule fails and you always get the default scenario.
OTP sent as a number ("otp": 123456)Still matches eq 123456 — values are compared as strings.
Two scenarios could both matchLower priority number wins. Give need-otp and success different priorities even though their rules are exclusive.
Scenario disabledSkipped during rule evaluation, silently. Check the toggle before debugging the rule.

Limitation: the mock has no memory

The mock engine is stateless per request. It decides purely from the request in front of it — an identical request always produces an identical response.

So if your app sends a second /login that is byte-for-byte identical to the first (no otpToken, no header, nothing), no match rule can tell the two apart. Two ways forward:

  1. Have the client carry the token — what real backends do anyway, and what makes the recipe above work.

  2. Flip the scenario between the calls — from the endpoint page in the dashboard, or programmatically:

    POST /api/projects/{projectId}/overrides
    Content-Type: application/json
    
    { "endpointId": "<uuid>", "sessionId": "<your-session-id>", "scenarioKey": "success" }

    The override is scoped to the X-Mock-Session header your client sends, so parallel testers do not collide. Note this endpoint authenticates with a logged-in dashboard session, not the project API key — it is meant for the dashboard and for test harnesses that can log in, not for the app under test.

On this page