"use client"; import PrimaryButton from "../PrimaryButton"; import { SymbolView, SymbolViewProps, SymbolWeight } from "expo-symbols"; import { useState } from "react"; import { Platform, StyleProp, ViewStyle } from "react-native"; const PASSKEY_CREDENTIAL_ID_KEY = "urbit_wallet_passkey_id"; const RELYING_PARTY_ID = "wallet.urbit.org"; // Change this to your domain const RELYING_PARTY_NAME = "Urbit Wallet"; export function Passkee() { const [isLoading, setIsLoading] = useState(false); async function handleCreatePasskey() { const pkok = await window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(); console.log({ pkok }); // if (Platform.OS !== "web") { // return false; // } console.log("creating passkey"); try { // Generate a random user ID const userId = new Uint8Array(16); crypto.getRandomValues(userId); // Generate a random challenge const challenge = new Uint8Array(32); crypto.getRandomValues(challenge); const createCredentialOptions: CredentialCreationOptions = { publicKey: { // REQUIRED: Random challenge to prevent replay attacks // Must be at least 16 bytes, we use 32 for extra security challenge, // REQUIRED: Relying Party (your website/app) rp: { // REQUIRED: Human-readable name shown in UI prompts name: RELYING_PARTY_NAME, // OPTIONAL: Domain that owns this credential // If omitted, defaults to current domain // Must match or be a registrable suffix of the current domain id: window.location.hostname === "localhost" ? "localhost" : RELYING_PARTY_ID, }, // REQUIRED: User information user: { // REQUIRED: Unique user ID (must not contain PII) // Used by authenticator to distinguish between accounts id: userId, // REQUIRED: Unique username/identifier for this RP // Shown in some UI contexts, should be recognizable to user name: "urbit-user", // REQUIRED: Human-readable name for display // Shown in account selectors and prompts displayName: "Urbit Wallet User", }, // REQUIRED: List of acceptable public key algorithms // Order matters - authenticator will use first supported algorithm pubKeyCredParams: [ { alg: -7, type: "public-key" }, // ES256 (ECDSA with SHA-256) - most common { alg: -257, type: "public-key" }, // RS256 (RSASSA-PKCS1-v1_5) - fallback ], // OPTIONAL: Criteria for authenticator selection authenticatorSelection: { // OPTIONAL: "platform" (built-in like Touch ID) or "cross-platform" (USB key) // Omitting allows both types // authenticatorAttachment: "platform", // OPTIONAL: User verification requirement // "required" - must verify user (biometric/PIN) // "preferred" - verify if possible, continue if not (default) // "discouraged" - don't verify unless required by RP userVerification: "preferred", // OPTIONAL: Whether to create a discoverable credential (passkey) // "required" - must create discoverable credential // "preferred" - create if possible (default) // "discouraged" - don't create discoverable credential residentKey: "preferred", // DEPRECATED: Use residentKey instead // Kept for backwards compatibility with older authenticators requireResidentKey: false, }, // OPTIONAL: Time limit in milliseconds (default varies by browser) // 60 seconds is reasonable for user interaction timeout: 60000, // OPTIONAL: Attestation preference (proof of authenticator legitimacy) // "none" - no attestation needed (default, best for privacy) // "indirect" - RP prefers attestation but allows anonymization // "direct" - RP needs attestation from authenticator // "enterprise" - RP needs attestation and device info (requires permission) attestation: "none", // OPTIONAL: List of credentials to exclude (prevent duplicates) // excludeCredentials: [ // { id: existingCredentialId, type: "public-key" } // ], // OPTIONAL: Extensions for additional features // extensions: { // credProps: true, // Request additional credential properties // hmacCreateSecret: true, // For symmetric key operations // }, }, }; const credential = (await navigator.credentials.create( createCredentialOptions, )) as PublicKeyCredential; console.log({ credential }); if (credential) { // Store the credential ID for later use // await SecureStore.setItemAsync(PASSKEY_CREDENTIAL_ID_KEY, credential.id); console.log("Passkey created successfully", credential.id); return true; } return false; } catch (error) { console.error("Error creating passkey:", error); return false; } } return ( ); }