The device signer is the default signer for client-side wallets. It generates a P256 keypair inside the device’s secure hardware — the iOS Secure Enclave, Android Keystore, or the browser’s Web Crypto API — so the private key never leaves the device. Transactions are signed silently, with no OTP or user confirmation required.
Device signers are not currently available for Solana. For Solana wallets, the recovery signer is used as a fallback for signing transactions.
In browser environments, the device signer key lives inside a hidden iframe hosted at crossmint-signer.io — a separate origin from your application. Key generation and signing happen inside the iframe via postMessage. Keys are stored as non-extractable CryptoKey objects in the iframe’s IndexedDB, isolated from the parent page by the browser’s same-origin policy.
On iOS, keys are stored in the Secure Enclave. On Android, keys are stored in the Android Keystore. Both provide hardware-level isolation for the private key material.
With a device signer, useSigner() is not needed — the device signer is auto-selected as the default. Transactions are signed without any user-facing prompts:
Device signers are per-device — they do not sync across devices. When a user accesses their wallet from a new device:
The user authenticates via your app (JWT) and the SDK retrieves the wallet
No local device signer exists on the new device, so wallet.needsRecovery() returns true
On the first transaction, the SDK automatically triggers recovery: the user verifies via their recovery signer (e.g., email OTP) to authorize a new device signer for this device
After recovery, all subsequent transactions on the new device are frictionless again
The previous device’s signer remains valid — each device maintains its own independent signer.
Recovery runs automatically before the first signing operation on a new device. If you want to trigger it earlier (e.g., on app startup to avoid an OTP prompt mid-transaction), call recover() explicitly: