[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › local‑first/Auth

Local-first auth: how [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp) unlocks an app's device database,
which keeps the AppOwners the app can open on this device, and Evolu's
AppOwner table there.

Only Evolu writes the AppOwner table; apps read and change it through
`EvoluApp`. The table is local-only: its rows never sync, keep no history,
and a delete removes the row. A row's `id` is the OwnerId its `secret`
derives, so storing the same secret again updates the same row. Its `ownerId`
system column is the device owner.

See docs/adr/evolu-creates-and-stores-app-owners.md.

## Auth

| Name                                                                                                                                    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [DeviceSecretAuth](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretAuth)                                         | [EvoluAppAuth](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/EvoluAppAuth) with a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret) the app keeps where only the user or the platform can unlock it, such as Electron's `safeStorage`.                                                                                                                                                                                                                                                                                                                                                      |
| [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider)                           | A source of the key that wraps an app's [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret), such as a passkey's PRF output, which `@evolu/web` provides. Creating or getting a key may prompt the user, which some browsers allow only in a user gesture. Its Tasks must end when their Run aborts them, such as by passing its signal to the prompt, because a setup holds the app's lock while it creates or gets a key, so a Task that keeps waiting holds up every tab's unlock. See [unlockWrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/unlockWrappedDeviceSecret). |
| [DeviceSecretKeyRefusedError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyRefusedError)                   | A [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider) refused to create or get a key, such as when the user dismissed its prompt or the key is gone. It can be temporary, such as a locked password manager that took the prompt over, so let the user try again.                                                                                                                                                                                                                                                                                                                     |
| [DeviceSecretKeyUnavailableError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyUnavailableError)           | A [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider) can't provide a key, such as for a passkey whose provider lacks the WebAuthn PRF extension.                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| [DeviceSecretUnwrapError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretUnwrapError)                           | A [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret) failed authentication in [unwrapDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/unwrapDeviceSecret): the key is another one, or the bytes changed. Or it holds 32 zero bytes, instant start's public secret, which isn't a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret).                                                                                                                                                                                               |
| [InstantStartAuth](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/InstantStartAuth)                                         | [EvoluAppAuth](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/EvoluAppAuth) without a prompt: the device database's key is public, so anything that can read the app's storage can read the AppOwner secrets kept there. The app database stays encrypted with its AppOwner.                                                                                                                                                                                                                                                                                                                                                      |
| [WrappedDeviceSecretNotPersistedError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/WrappedDeviceSecretNotPersistedError) | The platform keeps nothing, such as Safari's Private Browsing, so [unlockWrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/unlockWrappedDeviceSecret) creates no key: every start would create another one, such as another passkey in the user's password manager. See [DevicePersistence](https://evolu.dev/docs/api-reference/common/local-first/Evolu/type-aliases/DevicePersistence).                                                                                                                                                                                                                                     |
| [WrappedDeviceSecretStoredError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/WrappedDeviceSecretStoredError)             | [forgetWrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/forgetWrappedDeviceSecret) with `onlyPending` found a stored [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret) rather than a setup's pending key, so it forgot nothing. Forgetting a stored secret loses its device database, so the app asks the user to confirm and then forgets it without `onlyPending`.                                                                                                                                                                                          |
| [DeviceSecretKeyError](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/DeviceSecretKeyError)                               | An error of a [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| [DeviceSecretKeyId](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/DeviceSecretKeyId)                                     | The id of a key that wraps a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret), such as a passkey's credential ID, from 1 to 1023 bytes as WebAuthn allows.                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| [EvoluAppAuth](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/EvoluAppAuth)                                               | How [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp) unlocks the app's device database, which keeps the AppOwners the app can open on this device. Fixed per app, like [EvoluConfig.appName](https://evolu.dev/docs/api-reference/common/local-first/Evolu/interfaces/EvoluConfig#appname): another one opens another device database.                                                                                                                                                                                                                                                                            |
| [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/WrappedDeviceSecret)                                 | A [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret) wrapped by a key from a [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider): a 24-byte nonce, the 32-byte ciphertext, and its 16-byte authentication tag. The format is permanent once shipped.                                                                                                                                                                                                                                                                                              |
| [DeviceSecretKeyId](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecretKeyId)                                        | The id of a key that wraps a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret), such as a passkey's credential ID, from 1 to 1023 bytes as WebAuthn allows.                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret)                                    | A [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret) wrapped by a key from a [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider): a 24-byte nonce, the 32-byte ciphertext, and its 16-byte authentication tag. The format is permanent once shipped.                                                                                                                                                                                                                                                                                              |
| [wrappedDeviceSecretEvoluSchema](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/wrappedDeviceSecretEvoluSchema)              | Evolu's tables of the database that holds an app's [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret), whose key is public, because it must open before the [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret) exists. Its table and column names are permanent once shipped.                                                                                                                                                                                                                                                                             |
| [wrappedDeviceSecretTable](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/wrappedDeviceSecretTable)                          | The name of Evolu's table of an app's [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret). Permanent once shipped.                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| [unwrapDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/unwrapDeviceSecret)                                      | Authenticates and unwraps a [WrappedDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/WrappedDeviceSecret).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| [wrapDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/wrapDeviceSecret)                                          | Wraps a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret) with a key from a [DeviceSecretKeyProvider](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretKeyProvider). A fresh random nonce makes every wrap of the same secret different.                                                                                                                                                                                                                                                                                                                                             |

## Device

| Name                                                                                               | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [DeviceSecretError](https://evolu.dev/docs/api-reference/common/local-first/Auth/interfaces/DeviceSecretError)  | Error for 32 zero bytes, instant start's public secret, which isn't a [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret). It leaves the value out, as a secret's error should.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/type-aliases/DeviceSecret)          | The secret of an app's device database, which keeps the AppOwners the app can open on this device. Keep it where only the user or the platform can unlock it, as `loadDeviceSecret` of `@evolu/react-native` does, or in Electron's `safeStorage`. It isn't an [OwnerSecret](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerSecret): [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp) derives the device database's owner from it on paths no OwnerSecret reaches, so no AppOwner's ID or keys name or open the device database. Create it with [createDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/createDeviceSecret) and never use its bytes as an OwnerSecret: an AppOwner's mnemonic is its secret, so whoever holds it would derive the device database's key. 32 zero bytes are instant start's public secret, so the Type rejects them, also in [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp), which checks the secret it gets with the Type. |
| [appOwnerTable](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/appOwnerTable)           | The name of Evolu's AppOwner table. Permanent once shipped.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| [deviceEvoluSchema](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/deviceEvoluSchema)   | Evolu's tables of the device database. Its table and column names are permanent once shipped.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret)             | The secret of an app's device database, which keeps the AppOwners the app can open on this device. Keep it where only the user or the platform can unlock it, as `loadDeviceSecret` of `@evolu/react-native` does, or in Electron's `safeStorage`. It isn't an [OwnerSecret](https://evolu.dev/docs/api-reference/common/local-first/Owner/variables/OwnerSecret): [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp) derives the device database's owner from it on paths no OwnerSecret reaches, so no AppOwner's ID or keys name or open the device database. Create it with [createDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/createDeviceSecret) and never use its bytes as an OwnerSecret: an AppOwner's mnemonic is its secret, so whoever holds it would derive the device database's key. 32 zero bytes are instant start's public secret, so the Type rejects them, also in [createEvoluApp](https://evolu.dev/docs/api-reference/common/local-first/Evolu/functions/createEvoluApp), which checks the secret it gets with the Type. |
| [createDeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/functions/createDeviceSecret) | Creates a cryptographically random [DeviceSecret](https://evolu.dev/docs/api-reference/common/local-first/Auth/variables/DeviceSecret).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |