threshold1

Passkey

There's no raw-HTTP way to register or log in with a passkey from a backend, and this page says so directly rather than documenting six endpoints your Python/Ruby/Go/Java service could technically call but never meaningfully complete. What's actually usable standalone — listing and removing existing passkeys — is real, live-verified, and covered below.

Why the ceremony endpoints aren't documented here

Registering or logging in with a passkey is a WebAuthn ceremony: it needs a real browser's navigator.credentials API talking to a real platform authenticator (Touch ID, Windows Hello, a phone's biometric unlock). The /passkey/register/* and /passkey/login/* /verify endpoints each require a credential object — confirmed by reading every one of their route files directly — that only @simplewebauthn/browser's startRegistration()/startAuthentication() can produce, from inside a real browser, in response to a real user gesture. No backend in any language can construct that value. The /start half of each pair is technically callable on its own — it just returns WebAuthn challenge options — but calling it alone accomplishes nothing without a browser to complete the ceremony.

If you need passkey support, the JS SDK is the only real path — see Quickstart and Passkey.

What does work standalone: managing existing passkeys

These four are genuinely just CRUD against stored credentials — no WebAuthn ceremony involved, all live-verified against the real hosted API with a passkey registered through a real (automated) browser ceremony first.

List — by session

GET /api/v1/passkeys
Authorization: Bearer <threshold1_jwt>

Real response, captured live:

{
  "success": true,
  "passkeys": [
    { "credentialId": "I9CqlTr3aj1FqTrBTFvURg3LA_w2iJrspYk7UnH0G8o", "createdAt": "2026-08-25T18:06:57.911712" }
  ]
}

Delete — by session

DELETE /api/v1/passkeys/:credentialId
Authorization: Bearer <threshold1_jwt>

Real response: { "success": true }. A non-existent credentialId returns a real, captured error:

{ "success": false, "error": "Passkey not found.", "code": "PASSKEY_NOT_FOUND" }

404

List — by external ID

GET /api/v1/passkeys/by-external?externalUserId=your_user_123
Authorization: Bearer th_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API-key authenticated — no user JWT needed. Same response shape as the session-authenticated list above. Live-verified with a real passkey registered against a real externalUserId.

Delete — by external ID

DELETE /api/v1/passkeys/by-external/:credentialId?externalUserId=your_user_123
Authorization: Bearer th_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Real response: { "success": true }. Same use case as the session-authenticated delete, for when your backend manages passkeys on behalf of users identified by your own ID rather than a threshold1 session.

What's next

  • Passkey (Methods Reference) — the full method, including the domain setup real passkey login needs.
  • External User ID Bridging — how the by-external variants resolve to the right user.