Security
Passkeys and two-factor sign-in (dashboard only).
POST
/api/v1/security/login/passkeyPublic. Verifies the passkey signature and issues a Firebase custom token (signInWithCustomToken). The session counts as two-factor verified. Email verification and account approval are then checked as usual.
No authentication required.
Body (JSON)
challengeIdstringrequiredmax. 100 charactersresponseWebAuthnAuthenticationResponserequiredidstringrequiredmax. 4096 charactersrawIdstringrequiredmax. 4096 characterstype"public-key"requiredresponseobjectrequiredclientDataJSONstringrequiredmax. 4096 charactersauthenticatorDatastringrequiredmax. 4096 characterssignaturestringrequiredmax. 4096 charactersuserHandlestringmax. 1024 characters
authenticatorAttachmentstringclientExtensionResultsobjectDefault: {}
Response 200 · MfaSession
customTokenstringrequiredFirebase custom token. Sign in with signInWithCustomToken() – the new session counts as confirmed with two factors.method"passkey" | "totp" | "recovery_code"requiredexpiresAtstringrequiredUntil when the confirmation is valid; after that, the second factor is requested again.
curl -X POST 'https://www.debt-flow.io/api/v1/security/login/passkey' \
-H 'Content-Type: application/json' \
-d '{
"challengeId": "string",
"response": {
"id": "string",
"rawId": "string",
"type": "public-key",
"response": {
"clientDataJSON": "string",
"authenticatorData": "string",
"signature": "string",
"userHandle": "string"
},
"authenticatorAttachment": "string",
"clientExtensionResults": {}
}
}'Response 200
{
"customToken": "string",
"method": "passkey",
"expiresAt": "string"
}POST
/api/v1/security/login/passkey-optionsPublic. Returns the options for navigator.credentials.get() (discoverable passkeys, user verification required). Then POST /security/login/passkey.
No authentication required.
Response 200 · WebAuthnChallenge
challengeIdstringrequiredInclude when completingoptionsobjectrequiredPass to navigator.credentials (or @simplewebauthn/browser)expiresAtstringrequiredTimestamp (ISO 8601)
curl -X POST 'https://www.debt-flow.io/api/v1/security/login/passkey-options'Response 200
{
"challengeId": "string",
"options": {},
"expiresAt": "string"
}