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

# Authentication

> Meru-hosted end-user login — email OTP and native passkeys.

Login is **Meru-hosted**: the SDK talks directly to Meru's public auth endpoints
with your public company app id (no secret on the client). Meru returns a
**wallet-auth token** you pass as the `Bearer` on every wallet call.

## The auth client

<CodeGroup>
  ```ts React Native theme={null}
  import { createMeruAuth } from "@meru.app/device-signer/auth";

  const auth = createMeruAuth({
    authBase: "https://stablecoin-api.getmeru.com",
    companyId: "<your public company id>",
    passkeyDomain: "yourapp.com",
    storage: { /* getItem / setItem / removeItem */ },
  });
  ```

  ```dart Flutter theme={null}
  final auth = MeruAuth(
    authBase: 'https://stablecoin-api.getmeru.com',
    companyId: '<your public company id>',
    passkeyDomain: 'yourapp.com',
  );
  ```

  ```swift iOS theme={null}
  let auth = MeruAuth(
      authBase: URL(string: "https://stablecoin-api.getmeru.com")!,
      companyId: "<your public company id>",
      passkeyDomain: "yourapp.com"
  )
  ```

  ```kotlin Android theme={null}
  val auth = MeruAuth(
      context = applicationContext,
      authBase = "https://stablecoin-api.getmeru.com",
      companyId = "<your public company id>",
      passkeyDomain = "yourapp.com",
  )
  ```
</CodeGroup>

## Methods

| Call                           | What it does                                                        |
| ------------------------------ | ------------------------------------------------------------------- |
| `restore()`                    | Reload a persisted session at startup. Returns the session or null. |
| `sendEmailCode(email)`         | Send an email OTP. Returns a dev code only on local/dev backends.   |
| `verifyEmailCode(email, code)` | Verify the OTP → returns a session.                                 |
| `enablePasskey()`              | Turn on passkey sign-in for the signed-in user.                     |
| `loginWithPasskey(email?)`     | Sign in with a passkey (usernameless if omitted).                   |
| `logout()`                     | Clear the persisted session.                                        |

<Note>
  On **Android**, the passkey calls (`enablePasskey`, `loginWithPasskey`) take an
  **Activity** context, e.g. `auth.enablePasskey(activity)`.
</Note>

## Session persistence

The session is persisted in secure storage (Keychain / Keystore /
EncryptedSharedPreferences), so call `restore()` once at startup:

<CodeGroup>
  ```ts React Native theme={null}
  const session = await auth.restore(); // null if not signed in
  ```

  ```swift iOS theme={null}
  let session = auth.restore()
  ```

  ```kotlin Android theme={null}
  val session = auth.restore()
  ```
</CodeGroup>

Ready to add Face ID / Touch ID / fingerprint? See [Passkeys](/self-custody/passkeys).
