Supported Chains
| Chain | Operational signer | Recovery method |
|---|---|---|
| EVM | ✅ | ✅ |
| Stellar | ✅ | ✅ |
| Solana | ✅ | ❌ |
Configuration
Configure the wallet to use a passkey as the operational signer at creation time. The SDK handles WebAuthn registration during the first wallet creation.- React
- React Native
- Swift
- Kotlin
Using Or create the wallet explicitly:The same configuration works on Stellar and Solana: set
createOnLogin on the provider:import {
CrossmintProvider,
CrossmintAuthProvider,
CrossmintWalletProvider,
} from "@crossmint/client-sdk-react-ui";
function App({ children }) {
return (
<CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
<CrossmintAuthProvider loginMethods={["email", "google"]}>
<CrossmintWalletProvider
createOnLogin={{
chain: "base-sepolia",
recoveryMethods: [{ type: "email" }],
signers: [{ type: "passkey" }],
}}
>
{children}
</CrossmintWalletProvider>
</CrossmintAuthProvider>
</CrossmintProvider>
);
}
import { useWallet } from "@crossmint/client-sdk-react-ui";
const { createWallet } = useWallet();
const wallet = await createWallet({
chain: "base-sepolia",
recoveryMethods: [{ type: "email", email: "user@example.com" }],
signers: [{ type: "passkey" }],
});
chain to "stellar" or "solana". On Stellar a passkey can also be a recovery method (recoveryMethods: [{ type: "passkey" }]); on Solana it can only be an operational signer.Each transaction triggers a biometric authentication prompt.React Native uses the platform passkey APIs (iOS AuthenticationServices, Android Credential Manager) through the Without the
react-native-passkey package.1
Install the native module
Install
react-native-passkey and rebuild the app. Passkeys need a development build; Expo Go cannot run native modules.npx expo install react-native-passkey
2
Associate the app with the relying party domain
Associate the app with the domain you use as the relying party ID (
rpId):- iOS: add the associated domain
webcredentials:app.example.comto the app, and serve anapple-app-site-associationfile from the domain that lists the app. - Android: serve
/.well-known/assetlinks.jsonfrom the domain with thedelegate_permission/common.get_login_credsrelation for the app’s package name and signing certificate.
3
Configure passkeys on the wallet provider
Pass
passkeys to CrossmintWalletProvider. Pass Passkey from react-native-passkey so your bundler links the native module:import { Passkey } from "react-native-passkey";
import {
CrossmintProvider,
CrossmintAuthProvider,
CrossmintWalletProvider,
} from "@crossmint/client-sdk-react-native-ui";
function App({ children }) {
return (
<CrossmintProvider apiKey="YOUR_CLIENT_API_KEY">
<CrossmintAuthProvider loginMethods={["email", "google"]}>
<CrossmintWalletProvider
passkeys={{ rpId: "app.example.com", rpName: "Example", passkey: Passkey }}
createOnLogin={{
chain: "base-sepolia",
recoveryMethods: [{ type: "email" }],
signers: [{ type: "passkey" }],
}}
>
{children}
</CrossmintWalletProvider>
</CrossmintAuthProvider>
</CrossmintProvider>
);
}
Keep
rpId fixed once users have created passkeys. A passkey only works for the domain it was created for.passkeys prop, the React Native SDK rejects passkey signers. Every passkey operation requires user verification (biometrics or a device PIN).The Swift SDK uses the iOS passkey APIs (AuthenticationServices) and shows the system prompts for you. The steps below need a signed-in user; see the Swift quickstart to configure the SDK and sign the user in.The same configuration works on Stellar and Solana: use
1
Associate the app with the relying party domain
Add the associated domain
webcredentials:app.example.com to the app, and serve an apple-app-site-association file from the domain that lists the app. The SDK uses this domain (host) as the relying party ID.2
Create the wallet with a passkey signer
Pass a passkey in
signers. The SDK asks the user to create the passkey, then creates the wallet:import CrossmintClient
CrossmintSDK.configure(apiKey: "YOUR_CLIENT_API_KEY")
let sdk = CrossmintSDK.shared
let passkey = SignerConfig.passkey(name: "user@example.com", host: "app.example.com")
let wallet = try await sdk.crossmintWallets.createWallet(
chain: EVMChain.baseSepolia,
recoveryMethods: [EVMSigners.email("user@example.com")],
signers: [passkey]
)
try await wallet.useSigner(passkey)
name is the account name that the passkey prompt shows.3
Sign with the passkey on later launches
Set
passkeyHost when you get the wallet. The SDK then signs with the passkey:// Uses the SDK configured in the create step
import CrossmintClient
let wallet = try await CrossmintSDK.shared.crossmintWallets.getWallet(
chain: EVMChain.baseSepolia,
options: WalletOptions(passkeyHost: "app.example.com")
)
StellarChain.stellar or SolanaChain.solana. On Stellar a passkey can also be a recovery method (StellarSigners.passkey(name:host:)); on Solana it can only be a signer.The Kotlin SDK uses Android Credential Manager through the The same configuration works on Stellar and Solana: use
sdk-passkeys module. The steps below need a configured SDK and a signed-in user; see the Kotlin quickstart.1
Add the passkeys module
The
crossmint-sdk artifact does not include passkey support. Add sdk-passkeys with the same version:build.gradle.kts
dependencies {
implementation(libs.crossmint.sdk)
implementation(libs.crossmint.sdk.passkeys)
}
libs.versions.toml
[libraries]
crossmint-sdk-passkeys = { module = "com.crossmint:sdk-passkeys", version.ref = "crossmint-sdk" }
2
Associate the app with the relying party domain
Serve
/.well-known/assetlinks.json from the domain you use as the relying party ID (rpId), with the delegate_permission/common.get_login_creds relation for the app’s package name and signing certificate.3
Create the wallet with a passkey signer
Create the passkey with
createPasskeyCredential, and pass it in signers. AndroidPasskeyProvider shows the passkey prompt each time the wallet signs:import android.app.Activity
import androidx.credentials.CredentialManager
import com.crossmint.kotlin.CrossmintSDK
import com.crossmint.kotlin.passkeys.AndroidPasskeyProvider
import com.crossmint.kotlin.passkeys.createPasskeyCredential
import com.crossmint.kotlin.signers.DelegatedSigner
import com.crossmint.kotlin.signers.SignerType
import com.crossmint.kotlin.types.EVMChain
import com.crossmint.kotlin.types.getOrThrow
suspend fun createPasskeyWallet(activity: Activity) {
val credential = createPasskeyCredential(
name = "user@example.com",
activityProvider = { activity },
credentialManager = CredentialManager.create(activity),
rpId = "app.example.com",
rpName = "Example",
) ?: return
val wallet = CrossmintSDK.shared.wallets.createWallet(
chain = EVMChain.BaseSepolia,
recoveryMethods = listOf(SignerType.Email("user@example.com")),
signers = listOf(
DelegatedSigner.Passkey(
id = credential.id,
name = credential.name,
publicKeyX = credential.publicKeyX,
publicKeyY = credential.publicKeyY,
),
),
passkeyProvider = AndroidPasskeyProvider(rpId = "app.example.com"),
).getOrThrow()
}
createPasskeyCredential returns null when the user cancels or the passkey cannot be created.4
Sign with the passkey on later launches
Pass an
AndroidPasskeyProvider when you get the wallet. The SDK then signs with the passkey:// Uses the SDK configured at app start, as in the create step
import com.crossmint.kotlin.CrossmintSDK
import com.crossmint.kotlin.passkeys.AndroidPasskeyProvider
import com.crossmint.kotlin.types.EVMChain
import com.crossmint.kotlin.types.getOrThrow
val wallet = CrossmintSDK.shared.wallets.getWallet(
chain = EVMChain.BaseSepolia,
passkeyProvider = AndroidPasskeyProvider(rpId = "app.example.com"),
).getOrThrow()
StellarChain.Stellar or SolanaChain.Solana. On Stellar a passkey can also be a recovery method (SignerType.Passkey); on Solana it can only be a signer.Adding a Passkey to an Existing Wallet
If the wallet already exists with a different signer, you can add a passkey withaddSigner. See Add Signers for the full flow.
Next Steps
Add Signers
Register additional signers on an existing wallet
Configure Recovery
Set up email or phone recovery
Device Signer
The default client-side signer

