Migrating existing devices to hardware-backed keys
The constraint that forces the decision
A hardware-backed key cannot be imported. It must be generated inside the secure element — that is the entire security property. AndroidKeyStore and the Apple Secure Enclave both refuse to ingest an existing private scalar, and rightly so: a key that could be imported was, by definition, extractable at some point.
So there is no "upgrade the storage of the existing key" path. Concretely:
generate inside the element → new private key → new public key
→ the backend's registered key is stale
→ re-enrolmentAny device that already holds a key generated outside a secure element — a WebCrypto key from a browser build, a key from the desktop software fallback, or one generated by a predecessor of this plugin — has a public key registered with your backend. Moving that device to a hardware-backed key means generating a new key pair and re-registering the new public key; there is no way to move the existing one into hardware in place.
Why that is not a decision this plugin makes for you
Re-enrolment is application-specific: it may need a second factor, a fresh device-binding ceremony, or nothing more than a silent key rotation, depending on how your backend authenticates devices. Whatever it needs, it is not something this plugin can do invisibly — the moment a device's public key changes, the previous key stops being able to authenticate as that device until the new one is registered.
For a security-sensitive credential this is worth treating deliberately rather than automatically, because a migration path that runs on every device at once converts a gradual risk (some devices are on a weaker key) into a synchronised one (every device re-enrols simultaneously, and anything that goes wrong in the ceremony goes wrong for everyone at once).
What this plugin gives you to build a migration on
capabilities()— probe before you start. It answers whether a key generated on this device right now would be hardware-backed, without creating one.generateKey({ requireHardware: true })— fails loudly rather than silently returning a software key, so a ceremony cannot half-succeed into a weaker key than it promised.SecureKey.backing/hardwareBacked— honest reporting, so you can instrument what fraction of your fleet is already hardware-backed before deciding whether a migration is worth forcing.
There is deliberately no import path. The Flutter predecessor of this plugin had one, for adopting a scalar out of an app's existing secure storage into its software signer; it is not carried over here, because a Tauri app reaching this plugin is not migrating off an in-process Dart key, and an import API that can only ever produce a software key is a foot-gun that reads like a migration tool.
Common shapes a caller might build on top of this, roughly in order of how disruptive they are to a user:
- New installs only. New enrolments get a hardware key; existing devices keep whatever they have until they re-enrol for an unrelated reason (new device, reinstall, key rotation). No forced ceremony, but the fleet only improves as fast as devices turn over.
- Offer, don't force. Surface
hardwareBackedin a settings screen and let the user trigger re-enrolment when it suits them. - Gate a new capability on hardware backing. A newly introduced high-risk operation can require
hardwareBacked, giving users a concrete reason to re-enrol at a moment of their choosing rather than on a forced schedule. - Migrate on next launch. The most complete outcome and the most disruptive one: every existing device hits a re-enrolment ceremony at once. If you choose this, budget for a resumable ceremony (a device interrupted mid-migration must still be able to authenticate with its old key until the new one is confirmed registered), a way to halt the rollout, and a tested rollback.
Which of these is right depends entirely on your backend's authentication model and your users' tolerance for a re-enrolment prompt — this plugin deliberately does not pick one for you.
A note specific to the web and desktop targets
A browser or desktop build cannot produce a hardware key at all, so for those targets there is no migration to run: capabilities() reports software permanently, and generateKey({ requireHardware: true }) will always fail. A migration designed around "prompt every device to re-enrol onto hardware" needs a branch for those users that does something else — most simply, leaves them on the software key and records that fact, rather than looping them through a ceremony that cannot succeed.