> ## Documentation Index
> Fetch the complete documentation index at: https://docs.guile.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Passkey authentication

> Sign in with WebAuthn passkeys through Guile's unified challenge API

Passkeys let a user sign in with biometrics, a PIN, or a security key instead of a password. Guile exposes both flows through the same challenge endpoints OTP uses.

## What you do first

1. Confirm the browser supports WebAuthn (Chrome/Edge 108+, Safari 16+, Firefox 119+) before you offer passkeys.
2. Register at least one passkey for the user (`POST /auth/passkeyRegistrationOptions`, then create the credential, then `POST /auth/passkeys`).
3. Create a challenge with `POST /auth/challenges` and `method: "passkey"`.
4. Run WebAuthn on the device, then verify with `POST /auth/verifiedChallenges` and the assertion.
5. Store the access and refresh tokens the same way you would for OTP.

Label usernameless as "Sign in with passkey" and username-first as "Use passkey". Offer OTP on the same challenge endpoints when passkeys are unavailable.

Registration creates a discoverable credential (resident key) so usernameless sign-in works. Options use human-readable names (`relyingParty`, `publicKeyCredentialParameters`, `algorithm` values like `ES256`), map those to WebAuthn COSE ids in your client.

Supported algorithms: `ES256` (preferred for broad device support), `RS256`, `EdDSA`, `ES384`, `ES512`.

## States that matter

### Usernameless (recommended)

```mermaid theme={null}
sequenceDiagram
 participant User
 participant Client
 participant API
 participant Authenticator

 User->>Client: Click "Sign in with passkey"
 Client->>API: POST /auth/challenges (method: "passkey")
 API->>Client: WebAuthn options (empty allowCredentials)
 Client->>Authenticator: Request authentication
 Authenticator->>User: Show available passkeys
 User->>Authenticator: Select passkey & verify
 Authenticator->>Client: Return assertion
 Client->>API: POST /auth/verifiedChallenges (method: "passkey", assertion)
 API->>API: Extract credential ID from assertion
 API->>API: Identify user from credential
 API->>API: Verify assertion
 API->>Client: Access & refresh tokens
```

Omit the identifier. The API returns an empty `allowCredentials` list; the browser discovers passkeys on the device.

### Username-first

```mermaid theme={null}
sequenceDiagram
 participant User
 participant Client
 participant API
 participant Authenticator

 User->>Client: Enter email/phone
 Client->>API: POST /auth/challenges (method: "passkey", identifier)
 API->>Client: WebAuthn options (user's passkeys)
 Client->>Authenticator: Request authentication
 Authenticator->>User: Show user's passkeys
 User->>Authenticator: Select passkey & verify
 Authenticator->>Client: Return assertion
 Client->>API: POST /auth/verifiedChallenges (method: "passkey", assertion)
 API->>Client: Access & refresh tokens
```

Send `phoneNumber` or `emailAddress` on the challenge. Use this when the user prefers to enter an identifier, or as a fallback when usernameless fails.

All Guile passkeys are discoverable (`residentKey: "required"`). Users can list and delete passkeys, and register more than one device.

## When a call fails

Failures come back as problem documents. Open the `type` link for the cause, the
fix, and whether retrying is safe.

Common ones on this path:

* [Invalid Passkey Assertion](/problems/invalidPasskeyAssertion): offer OTP on the same challenge API
* [Passkey Already Registered](/problems/passkeyAlreadyRegistered): list existing passkeys before registering again
* [Challenge Expired](/problems/challengeExpired): create a new passkey challenge
* [Unauthorized](/problems/unauthorized): refresh or sign in again before manage calls

## Related paths

* [Authentication overview](/api-reference/Authentication/overview): tokens and OTP
* [Problem types](/api-reference/problems): how to read a failure
