Device proof
When the phone holds a hardware key (Secure Enclave / Android Keystore), every approval carries approvalProof: the phone's own ECDSA P-256 signature over the request id, action, number-match code and the exact details it showed. Verify it on your server — you don't have to trust Touchque.
Pin the device: store
proof.publicKey from the user's first verified approval and pass it as the expected key. Without a pin the check returns false unless you explicitly allow an unpinned key (trust on first use only).Python needs the optional extra: touchque-authenticator[proof] (the cryptography package). PHP needs ext-openssl; Node, Go, .NET, Java and Ruby use their standard library.
In your webhook / after a status check
const { verifyApprovalProof } = require('@touchque/node');
const ok = verifyApprovalProof(event.approvalProof, {
requestId, type: 'WITHDRAW', details, challengeCode,
expectedPublicKey: user.touchqueDeviceKey, // stored from their first verified approval
});
if (!ok) throw new Error('approval proof does not match');# pip install "touchque-authenticator[proof]"
from touchque import verify_approval_proof
ok = verify_approval_proof(
event['approvalProof'], request_id=request_id, type='WITHDRAW',
details=details, challenge_code=challenge_code,
expected_public_key=user.touchque_device_key,
)use Touchque\ApprovalProof;
$ok = ApprovalProof::verify($event['approvalProof'] ?? null, [
'requestId' => $requestId, 'type' => 'WITHDRAW', 'details' => $details,
'challengeCode' => $challengeCode,
'expectedPublicKey' => $user->touchque_device_key,
]);ok := touchque.VerifyApprovalProof(event["approvalProof"], touchque.VerifyApprovalProofOptions{
RequestID: requestID, Type: "WITHDRAW", Details: details, ChallengeCode: challengeCode,
ExpectedPublicKey: user.TouchqueDeviceKey,
})var ok = ApprovalProof.Verify(e["approvalProof"] as JsonObject, new ApprovalProofOptions
{
RequestId = requestId, Type = "WITHDRAW", Details = details, ChallengeCode = challengeCode,
ExpectedPublicKey = user.TouchqueDeviceKey, // stored from their first verified approval
});boolean ok = ApprovalProof.verify(event.get("approvalProof"), new ApprovalProof.Options(requestId, "WITHDRAW")
.details(details).challengeCode(challengeCode)
.expectedPublicKey(user.getTouchqueDeviceKey())); // stored from their first verified approvalok = Touchque::ApprovalProof.verify(
event["approvalProof"], request_id: request_id, type: "WITHDRAW",
details: details, challenge_code: challenge_code,
expected_public_key: user.touchque_device_key
)