Mysten Labs SDKs
Cryptography

Passkey

Similar to other Keypair classes, the Sui TypeScript SDK provides the PasskeyKeypair that handles communication with the passkey device and signing with it. This SDK defines the address and signatures according to SIP-9.

To use, import the PasskeyKeypair class from @mysten/sui/keypairs/passkey.

import {
	BrowserPasskeyProvider,
	BrowserPasswordProviderOptions,
	PasskeyKeypair,
} from '@mysten/sui/keypairs/passkey';

Create a new passkey

To create a new passkey with the passkey device, and initialize a PasskeyKeypair, you can use the PasskeyProvider and provide the rpName, rpId and additional options. Note that getPasskeyInstance call will initialize a new passkey wallet for the origin.

const keypair = await PasskeyKeypair.getPasskeyInstance(
	new BrowserPasskeyProvider('Sui Passkey Example', {
		rpName: 'Sui Passkey Example',
		rpId: window.location.hostname,
		authenticatorSelection: {
			authenticatorAttachment: 'cross-platform', // or "platform"
		},
	} as BrowserPasswordProviderOptions),
);

You can optionally specify the authenticatorSelection parameter when creating a passkey instance:

  • cross-platform: Use this for authenticators that work across devices, such as hardware security keys or mobile phones.
  • platform: Use this for authenticators tied to a specific device, such as Touch ID, Face ID, or Windows Hello.

Because a passkey device will only return the public key upon creation, but not upon signing, it is recommended for the frontend to always cache the PasskeyKeypair instance that contains the public key in the wallet. When a user tries to sign a transaction, it will just call signTransaction on the same instance and the public key is available when constructing the passkey signature.

It is recommended that the user should only be allowed to create a passkey wallet once per origin. If the user ended up with multiple passkeys for the same origin, the passkey UI would show a list of all passkeys of the same origin and the user can choose which one to use. This can be a confusing experience since they do not remember which passkey is the way that the wallet was created for.

Recover a passkey

However, if the user is logged out or uses a different browser or device, or the PasskeyKeypair instance is no longer present for any reason, the user should be prompt to recover the public key (e.g. "Log in to existing passkey wallet") to be able to use the passkey wallet again. If the user is prompted to create a new key in passkey device, a fresh new wallet with new address will be created.

One can recover the unique public key with exactly two passkey signatures on two messages. This means that if the user is asked to sign two messages, the developer can recover an unique public key and its Sui address.

let provider = new BrowserPasskeyProvider('Sui Passkey Example', {
	rpName: 'Sui Passkey Example',
	rpId: window.location.hostname,
} as BrowserPasswordProviderOptions);

const testMessage = new TextEncoder().encode('Hello world!');
const possiblePks = await PasskeyKeypair.signAndRecover(provider, testMessage);

const testMessage2 = new TextEncoder().encode('Hello world 2!');
const possiblePks2 = await PasskeyKeypair.signAndRecover(provider, testMessage2);

const commonPk = findCommonPublicKey(possiblePks, possiblePks2);
const keypair = new PasskeyKeypair(commonPk.toRawBytes(), provider);

Alternatively, the developer can choose to ask the user to only sign one personal message that returns two possible public keys. Then the frontend may derive the addresses for both, and check onchain for the unique address that contains assets. Or the frontend may retrieve additional signatures from past transaction history for the given address. This may a preferred user experience since the user is only prompted to sign one message, but the frontend needs to do extra work.

Usage

The usage for a passkey keypair is the same as any other keypair. You can derive the public key, derive the address, sign personal messages, sign transactions and verify signatures. See the Key pairs documentation for more details.

const publicKey = keypair.getPublicKey();
const address = publicKey.toSuiAddress();

const message = new TextEncoder().encode('hello world');
const { signature } = await keypair.signPersonalMessage(message);

const txSignature = await passkey.signTransaction(txBytes);

An example implemention can be found here.

Supported Platforms

Sui supports passkey wallets on any device that complies with the WebAuthn standard. This includes most modern browsers and operating systems across desktop and mobile. To check which platforms and authenticators are compatible, see the Passkeys.dev device support list.