# Identity-Backed Encryption

Identity-backed encryption lets users unlock their embedded wallets by signing in, with no authenticator to set up or lose. It is the recommended setup for most apps.

Each user's client-side MPC keyshare is encrypted with their Data Encryption Key (DEK). Identity-backed encryption wraps the DEK with a cloud key management service (KMS) key that MoonPay operates. The KMS only decrypts for a request that proves it is acting for one specific user of one specific app, so the user's signed-in identity is what unlocks it. A user with a usable identity-backed wrap can unlock their wallet by signing in, including after losing every device and passkey.

Users can also enroll passkeys, which wrap the same DEK. Without identity-backed encryption, an enrolled passkey is the only way to unlock the DEK, and losing every passkey and synced copy makes the client share unrecoverable. See [Passkeys & Key Protection](/wallets/passkeys).

This page covers the model, the tradeoff, and how to enable it. For the React SDK recipe that makes it the default for every account, see [Identity-First Setup](/wallets/identity-first-setup).

<Info>
  Both wraps protect one DEK. Enabling identity-backed encryption does not replace passkeys or weaken an existing passkey wrap, and a user can hold both at once. Either wrap opens the same DEK.
</Info>

## What this changes for your users

* They can read and write wallet keyshares, prove key ownership, and sign, using only their current session. No passkey prompt.
* If they have no passkeys at all, an email OTP can also serve as a presence proof.
* Losing every passkey no longer means losing the wallet, as long as they can still sign in.
* They can still enroll passkeys later, and adding one does not remove the identity wrap.

## What this does not change

Standard signing remains 2-of-2 MPC between the client share and the server-side signer share. The full private key is not assembled during signing. Identity-backed encryption changes access to the client share by adding a MoonPay-operated KMS route. See [MPC key custody](/security/key-custody).

Sensitive operations still require a fresh presence proof. Identity-backed encryption widens what can *produce* that proof; it does not remove the requirement.

## The trust tradeoff

This is a different guarantee from a passkey wrap, not a strictly better one, and it is worth stating plainly before you enable it.

* With a **passkey wrap**, the wrapping secret stays within the user's authenticator and wallet runtime. MoonPay does not hold that secret.
* With an **identity-backed wrap**, unwrapping depends on a KMS key that MoonPay operates. The release of that decryption is bound to the individual user, and each ciphertext is bound to the app and user it was created for, so one user's wrap cannot be used to open another's, and one app's wrap cannot be used in another app. But MoonPay operates the key, so MoonPay is in the unwrap path.

Identity-backed encryption allows recovery through sign-in but adds trust in MoonPay's KMS and identity authorization. See the [security model](/security/identity-backed-encryption) for account-compromise risks and the effect of keeping both wraps.

<Warning>
  Identity-backed encryption ties wallet access to the account a user signs in with. Anyone who can take over that account can unlock the wallet without a passkey. Account-recovery strength becomes wallet-recovery strength, so treat your sign-in flow accordingly.
</Warning>

## Presence proofs

A presence proof is a short-lived token that authorizes one sensitive operation. What a proof can authorize depends on how it was produced.

| Operation | Passkey assertion | Email OTP | Session alone |
| --- | --- | --- | --- |
| Read a wallet keyshare | Yes | Yes | Yes |
| Write a wallet keyshare | Yes | Yes | Yes |
| Prove key ownership | Yes | Yes | Yes |
| Sign | Yes | Yes | Yes |
| Provision or re-provision an ephemeral signer | Yes | Yes | Yes |
| Revoke an ephemeral signer | Yes | Yes | Yes |
| Export a private key | Yes | Yes | No |
| Enroll a passkey | Yes | Yes | No |
| Add a wrap | Yes | Yes | No |
| Remove the identity-backed wrap | Yes | No | No |

For an existing DEK, email OTP and session proofs require enabled, available identity-backed encryption and a usable identity-backed wrap. Email OTP also requires no enrolled passkeys and a verified email address. An eligible session can authorize signer provisioning and revocation without email OTP or a verified email address.

The SDK prefers an enrolled passkey. If the assertion fails or the user cancels it, an eligible session can authorize supported operations. See [Set up an identity-backed signer](/wallets/ephemeral-signers/identity-backed-setup) for the setup flow.

See [Presence Tokens](/authentication/user-authentication/presence-tokens) for the developer-facing flow.

## Removing passkeys and wraps

Two rules keep a user from stranding themselves:

1. A user may remove their **last** passkey when a usable identity-backed wrap remains. Without identity-backed encryption this is refused, because it would leave the DEK unopenable.
2. Removing the **identity-backed wrap** always requires a passkey assertion. A session cannot authorize it, and neither can an email OTP, because that would let the weaker proof destroy the stronger one's only alternative.

Together these mean a user can end up passkey-only, or identity-only, but not with nothing.

## Enabling it

### Why enable it

Enable identity-backed encryption when you want users to keep their wallets as long as they can sign in. Users do not need to enroll an authenticator before they can use a wallet, and losing a device or every passkey no longer means losing the wallet. Passkeys remain available for users who want to enroll them.

Before you enable it, make sure your sign-in flow is strong enough to protect wallets. Anyone who can take over a user's account can unlock that user's wallet. See [the trust tradeoff](#the-trust-tradeoff).

### In the dashboard

Identity-backed encryption runs on shared MoonPay infrastructure, so there are no keys or cloud resources to set up. Organization owners and admins can turn it on per app:

1. Open the app in the dashboard and go to its **Wallets** page.
2. In the **Identity-backed encryption** card, turn on **Enable identity-backed encryption**.
3. Confirm the prompt.

Enable it separately for each app you ship this way, including development and staging apps.

<Frame caption="The identity-backed encryption settings on an app's Wallets page">
  <img src="/images/screens/console-identity-backed-encryption.png" />
</Frame>

The same card holds [wallet unlock prewarm](/security/dek-prewarm), which is off by default and is available once identity-backed encryption is on.

### With the management API

With an [organization API key](/get-started/rest-api/organization-api-keys) that has the `config.write` scope, turn it on from your backend:

```bash
curl --fail-with-body \
	-X PUT "https://x-api.moonpay.com/v0/management/apps/$APP_ID/integrations/kms-wrap/managed" \
	-H "Authorization: Bearer $MOONX_ORG_API_KEY" \
	-H 'Content-Type: application/json' \
	--data '{"enabled":true}'
```

The response is the app's KMS configuration with `enabled` set. `GET /v0/management/apps/{appID}/integrations/kms-wrap` with the `config.read` scope returns the current state.

| Response | Meaning |
| --- | --- |
| `409 kms_wrap_in_use` | The app cannot be turned off because users rely on it. See [Turning it off](#turning-it-off) |
| `409 kms_wrap_custom` | The app uses its own KMS configuration, which this endpoint does not change |
| `503` | Identity-backed encryption is not available for the app. Contact MoonPay |

### After enabling

Turning it on for the app does not give existing users an identity-backed wrap. Use `enableAccountRecovery()` as shown in [Identity-First Setup](/wallets/identity-first-setup).

Once an app has stored its first identity-backed wrap, the KMS configuration behind it is fixed for that app. Changing it would orphan every wrap already created.

### Turning it off

You can turn identity-backed encryption off in the same card, or by sending `{"enabled": false}` to the same endpoint, until users rely on it. Once any user can unlock their wallet only with identity-backed encryption, turning it off returns `409 kms_wrap_in_use` until each of those users enrolls a passkey. Turning it off would otherwise leave those users unable to unlock their wallets.

While it is off, users unlock with their passkeys. Turning it back on restores identity-backed unlock for users who already hold a wrap.

If the card says the app uses its own KMS configuration, the switch is not shown. Contact MoonPay to change that configuration.

## Related

<CardGroup cols={2}>
  <Card title="Identity-backed security model" icon="shield-check" href="/security/identity-backed-encryption">
    The KMS trust model, recovery limits, and session-authorized signer actions.
  </Card>

  <Card title="Identity-First Setup" icon="rocket" href="/wallets/identity-first-setup">
    The React SDK recipe: turn it on at signup, gate wallet actions on either wrap, and offer passkeys as an upgrade.
  </Card>

  <Card title="Passkeys & Key Protection" icon="key" href="/wallets/passkeys">
    How the passkey wrap works, the enrollment and deletion lifecycle, and what happens when passkeys are lost.
  </Card>

  <Card title="Passkeys and recovery" icon="shield-check" href="/security/passkeys-and-recovery">
    The recovery model these two wraps sit inside.
  </Card>

  <Card title="Presence Tokens" icon="lock" href="/authentication/user-authentication/presence-tokens">
    Minting and verifying the short-lived proofs that gate sensitive operations.
  </Card>

  <Card title="MPC key custody" icon="server" href="/security/key-custody">
    Why unwrapping a DEK is not the same as being able to sign.
  </Card>
</CardGroup>
