Passkeys are for people, not servers. The token a passkey returns only works inside the dashboard (since 15 October 2026). Backends and scripts must use a team API key instead. The oldaccount_id+app_secretlogin is deprecated. See Move from login tokens to API keys.
- Overview
- Environments
- Where passkeys work
- Authentication
- Response envelope
- Registration flow
- Sign-in flow
- Using the token
- Confirming a sensitive action
- Passkey management
- Errors
- Frontend example
- Security notes
Overview
Passkeys follow the WebAuthn Level 2 standard. There are two flows:
A user has to sign in once another way (email one-time code) before they
can register a passkey. Every person on a team registers their own
passkeys and signs in as themselves: the team owner and each invited
member have separate passkeys, and a member’s passkey signs in to that
member’s own account.
Dashboard sign-in options today:
Environments
All paths below include
/api/v1. Passkeys are stored per environment, so a
passkey registered in sandbox doesn’t work in production.
Where passkeys work
The relying party ID (rp.id / rpId) is yativo.com. Browsers only
allow a WebAuthn ceremony for that ID on a page served from yativo.com or
one of its subdomains, such as https://app.yativo.com.
- Run the browser part (
navigator.credentials.create()/.get()) on a*.yativo.compage. On any other origin, includinglocalhost, the browser rejects it with aSecurityError. - A passkey registered from one Yativo subdomain works on the others.
Authentication
-
Registration and management endpoints need the signed-in person’s
bearer token, sent from the dashboard. They act on that person’s own
passkeys, whatever their team role. They can’t be called with an API key
(
403 This endpoint cannot be used with an API key. ...). -
Sign-in endpoints (
/auth/passkeys/authenticate/optionsand/auth/passkeys/authenticate) are public. -
Send cookies. The challenge from each “options” call is kept in the
session, so the options call and the call that follows it must share the
session cookie. With
fetch, setcredentials: 'include'.
Response envelope
Every endpoint returns the standard envelope. Success responses come back with HTTP200, even when the body says "status_code": 201, so check
status in the body. Errors come back with their real HTTP status.
Registration flow
1. Get registration options
- Allowed algorithms: ES256 (
-7), ES512 (-36), RS256 (-257), EdDSA (-8) and ES384 (-35). userVerificationisrequired: the device always asks for Face ID, a fingerprint, or a PIN, not just a tap.excludeCredentialslists the user’s existing passkeys so the same device isn’t registered twice.
2. Create the credential in the browser
3. Save the credential
Sign-in flow
1. Get sign-in options
account_id is the user’s email, base64-encoded (standard base64, not
base64url).
2. Sign the challenge in the browser
3. Send the signed challenge
expires_in is the token lifetime in seconds. Use the value returned rather
than hard-coding it.
Using the token
The passkey token is the same kind of token as the email one-time code login, and the same rules apply:- Send it as
Authorization: Bearer <access_token>. - It only works from the dashboard. Since 15 October 2026, a request with
a bearer token whose
Origin(orReferer) isn’thttps://app.yativo.comgets403 Bearer tokens are only accepted from the Yativo dashboard. ... - It expires after 5 minutes without a request, even before
expires_in, with401 Session expired due to inactivity. Please log in again.Send the user back to sign in. - A team member’s token acts on the team’s account, limited by their role. See Team Functionality.
Confirming a sensitive action
Account-recovery actions ask the signed-in person to confirm with one of their passkeys: resetting 2FA and resetting the transaction PIN. This is a “step-up” check, not a sign-in.-
Get a challenge for the signed-in person (bearer token required):
The response has the same
public_keyshape as sign-in options. It returns422 No passkeys registered for this account.when the person has no passkey. Limited to 10 requests per minute. -
Sign it in the browser with
navigator.credentials.get(), exactly as in sign-in step 2. -
Send the signed result with the recovery request, nested under
passkey:
timeout milliseconds (60
seconds). If the request fails, get a new challenge before retrying.
Passkey management
All management endpoints need the signed-in user’s bearer token.List passkeys
Rename a passkey
Delete a passkey
Errors
Challenges expire after 60 seconds and can only be used once. Request new
options right before prompting the user.
Frontend example
window.PublicKeyCredential before showing passkey options, and
always keep email code sign-in available as a fallback.
Security notes
- Challenges are single-use and expire after 60 seconds.
- Origin binding: passkeys are bound to
yativo.com, so they can’t be used on phishing sites on other domains. - Several passkeys: each person can register one per device. Encourage clear names and removing passkeys for devices they no longer have.

