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

# Passkeys (WebAuthn)

> Passwordless authentication with passkeys and WebAuthn.

# Passkeys (WebAuthn)

Passkeys use the [WebAuthn](https://webauthn.guide/) standard for phishing-resistant, passwordless authentication. Users sign in with a fingerprint, Face ID, or hardware security key. No passwords to forget or leak.

## How It Works

Steward's passkey flow is smart: it tries login first, and if the user doesn't have a passkey registered, automatically falls back to registration.

```
1. User enters email
2. SDK calls POST /auth/passkey/login/options
3. If user exists → browser prompts for passkey → verify → JWT
4. If user is new (404) → browser prompts to create passkey → register → JWT
```

The entire flow is a single SDK call.

## SDK Usage

```typescript theme={null}
import { StewardAuth } from "@stwd/sdk";

const auth = new StewardAuth({
  baseUrl: "https://api.steward.fi",
  storage: localStorage,
});

// One call handles both registration and login
const result = await auth.signInWithPasskey("user@example.com");

console.log(result);
// {
//   token: "eyJhbGci...",        // 15-min access token
//   refreshToken: "stwd_rt_...", // 30-day refresh token
//   expiresIn: 900,
//   user: { id: "usr_...", email: "user@example.com", walletAddress: "0x..." }
// }
```

<Warning>
  Passkeys require a **browser environment** with WebAuthn support. Calling `signInWithPasskey` in Node.js throws an error. Use `signInWithEmail` or `signInWithSIWE` for server-side auth.
</Warning>

## React Usage

The `<StewardLogin>` component includes passkey support by default:

```tsx theme={null}
import { StewardProvider, StewardLogin } from "@stwd/react";

function LoginPage() {
  return (
    <StewardProvider
      client={client}
      agentId="my-agent"
      auth={{ baseUrl: "https://api.steward.fi" }}
    >
      <StewardLogin
        showPasskey       // enabled by default
        showEmail={false} // hide email if you only want passkeys
        showGoogle={false}
        showDiscord={false}
        title="Welcome"
        onSuccess={(result) => console.log("Signed in:", result.user)}
      />
    </StewardProvider>
  );
}
```

## Peer Dependency

The SDK dynamically imports `@simplewebauthn/browser` for the WebAuthn ceremony. Install it as a peer dependency:

```bash theme={null}
npm install @simplewebauthn/browser
```

If the package is missing, `signInWithPasskey` throws a clear error message.

## Server Configuration

To enable passkeys on your self-hosted Steward instance, set these environment variables:

```bash theme={null}
# The relying party ID — usually your domain (no protocol, no port)
PASSKEY_RP_ID=myapp.com

# The expected origin for WebAuthn ceremonies
PASSKEY_ORIGIN=https://myapp.com

# Display name shown in the browser's passkey dialog
PASSKEY_RP_NAME="My App"
```

<Note>
  `PASSKEY_RP_ID` must match the domain where your app is served. For local development, use `localhost` and set `PASSKEY_ORIGIN=http://localhost:3000`.
</Note>

## API Endpoints

| Endpoint                         | Method | Description                                                             |
| -------------------------------- | ------ | ----------------------------------------------------------------------- |
| `/auth/passkey/login/options`    | POST   | Get WebAuthn authentication options for an existing user                |
| `/auth/passkey/login/verify`     | POST   | Verify a WebAuthn authentication response                               |
| `/auth/passkey/register/options` | POST   | Get WebAuthn registration options for a new user                        |
| `/auth/passkey/register/verify`  | POST   | Verify a WebAuthn registration response                                 |
| `/auth/mfa/passkey/options`      | POST   | Get session-bound passkey MFA options for the signed-in user            |
| `/auth/mfa/passkey/complete`     | POST   | Complete passkey MFA step-up and receive a refreshed recent-MFA session |

Login and registration endpoints accept `{ email, tenantId? }` in the request body.
MFA endpoints require the current bearer session; the options response includes
`challengeId`, and completion sends `{ challengeId, response }`.

## Browser Support

Passkeys are supported in all modern browsers:

* Chrome 67+
* Safari 14+
* Firefox 60+
* Edge 18+

On mobile, passkeys integrate with the platform's credential manager (iCloud
Keychain on iOS, Google Password Manager on Android). `@stwd/react-native`
exposes native bridge helpers for passkey login, registration, and MFA step-up:
your app supplies a platform credential-manager adapter with
`startAuthentication()` and `startRegistration()`, and Steward handles the API
challenge/verification/session exchange.

## Related

* [Auth Overview](/auth/overview) — How auth works in Steward
* [Email Magic Link](/auth/email) — Alternative for non-WebAuthn environments
* [React Components](/sdk/react-components) — `<StewardLogin>` reference
