/v1/auth/token/two-factor/passkey-optionsA passkey answer has to be signed over a challenge this API issued, so ask for
one before showing the system sheet. Send the challenge from
the first step and nothing else: who is signing in and
which passkeys they have are read from it.
Only passkeys registered through an app are listed. A passkey somebody made on their firm's website is bound to that domain, and an app can neither see it nor ask for it.
Request
curl https://api.proppertrading.com/v1/auth/token/two-factor/passkey-options \
-H "Content-Type: application/json" \
-d '{
"challenge": "a14ea608e89261062f4e90792701ef2a7c5ad1188c8537108efd788d1390ce03"
}'
| Field | Type | Description |
|---|---|---|
challenge | string | From the sign-in response. Required |
Response
The publicKey half of a WebAuthn request, ready to hand to the platform. Field
names are WebAuthn's, not ours.
{
"data": {
"object": "passkey_request_options",
"challenge": "3q2-7_8",
"timeout": 60000,
"rpId": "proppertrading.com",
"userVerification": "required",
"allowCredentials": [{ "id": "AQIDBA", "type": "public-key" }]
},
"meta": { "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey" }
}
The challenge inside these options is spent by the next answer, right or wrong. Ask again rather than reusing them.
rpId is ours and stays ours whichever firm the account belongs to. The system
sheet on the phone names it, which is the trade this design makes.
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | expired_two_factor_challenge | The sign-in challenge is gone, or the account has no passkey an app can use |
| 429 | rate_limit_exceeded | Twenty attempts per ten minutes per address, shared with the answer itself |
| 422 | validation_failed | No challenge, or a malformed one |
One reason, two causes
An expired challenge and an account without an app passkey answer the same. From outside there is one thing to do about either: start the sign-in again.