Low-level Client-Side SDK

The Virto Client SDK provides functionalities that allow web applications to interact with the blockchain using WebAuthn authentication directly from the browser. This SDK is designed to run in browser environments and leverages native WebAuthn APIs.

Configuration

import SDK from '@virtonetwork/sdk';

const sdk = new SDK({
  federate_server: 'https://your-federate-server.com/api',
  provider_url: 'wss://your-blockchain-provider:12281',
  config: {
    wallet: 'polkadotjs'  // Wallet type to use (polkadotjs or virto)
  }
});

Authentication Methods

The sdk.auth object provides the following methods:

register(user)

Registers a new user using a WebAuthn passkey. This method is only available in browser environments as it uses WebAuthn APIs.

Parameters:

  • user: Object containing the user profile and metadata

    {
      profile: {
        id: string,      // Required: Unique identifier for the user (e.g., email)
        name: string,    // Optional: User's full name
      }
    }

Returns: Promise that resolves with the registration response, including the blockchain address.

Example:

try {
  const result = await sdk.auth.register({
    profile: {
      id: "alice@example.com",
      name: "Alice Smith"
    }
  });
  console.log(`User registered with address: ${result.address}`);
} catch (error) {
  console.error("Registration error:", error.message);
}

prepareRegistration(user)

Prepares registration data on the client side using WebAuthn. This method is used internally by register(), but can be useful for custom authentication flows.

Parameters:

  • user: Object containing the user profile and metadata (same format as register)

Returns: Promise that resolves with the prepared registration data.

Example:

try {
  const preparedData = await sdk.auth.prepareRegistration({
    profile: {
      id: "alice@example.com",
      name: "Alice Smith"
    }
  });
  
  // The prepared data can be sent to your server
  console.log("Prepared registration data:", preparedData);
} catch (error) {
  console.error("Error preparing registration:", error.message);
}

connect(userId)

Authenticates a user with their existing passkey and establishes a session. This method is only available in browser environments.

Parameters:

  • userId: String - The unique identifier for the user (the same as profile.id used during registration)

Returns: Promise that resolves to an object containing session information.

Example:

try {
  const session = await sdk.auth.connect("alice@example.com");
  console.log(`Session established for user: ${session.userId}`);
  console.log(`Blockchain address: ${session.address}`);
} catch (error) {
  console.error("Connection error:", error.message);
}

prepareConnection(userId)

Prepares connection data on the client side using WebAuthn. This method is used internally by connect(), but can be useful for custom authentication flows.

Parameters:

  • userId: String - The unique identifier for the user

Returns: Promise that resolves with the prepared connection data.

Example:

try {
  const preparedData = await sdk.auth.prepareConnection("alice@example.com");
  
  // The prepared data can be sent to your server
  console.log("Prepared connection data:", preparedData);
} catch (error) {
  console.error("Error preparing connection:", error.message);
}

isRegistered(userId)

Checks if a user is already registered with the federate server.

Parameters:

  • userId: String - The unique identifier for the user

Returns: Promise that resolves to a boolean indicating if the user is registered.

Example:

try {
  const exists = await sdk.auth.isRegistered("alice@example.com");
  if (exists) {
    console.log("User is already registered, proceed to connect");
  } else {
    console.log("User needs to register first");
  }
} catch (error) {
  console.error("Error checking registration:", error.message);
}

sign(userId, command)

Signs a blockchain extrinsic using the user's active session.

Parameters:

  • userId: String - The unique identifier for the user

  • command: Object containing the extrinsic details

    {
      hex: string,    // Required: Hexadecimal representation of the extrinsic
      url: string,    // Optional: URL endpoint for the extrinsic
      body: any       // Optional: Additional data for the request
    }

Returns: Promise that resolves to an object containing the signed extrinsic.

Example:

// Hexadecimal representation of the extrinsic
const extrinsic = "0x1234..."; 

try {
  const signed = await sdk.auth.sign("alice@example.com", {
    hex: extrinsic,
  });

  console.log("Original extrinsic:", signed.originalExtrinsic);
  console.log("Signed extrinsic:", signed.signedExtrinsic);
} catch (error) {
  console.error("Signing error:", error.message);
}

Authentication Flow

The typical flow for implementing authentication with the Virto SDK is:

  1. Verify registration: Use isRegistered() to check if the user is already registered

  2. Registration (if necessary): If not registered, use register() to create a new passkey

  3. Connection: Use connect() to authenticate the user with their existing passkey

  4. Sign transactions: Once connected, use sign() to sign blockchain transactions

async function authenticateUser(userId) {
  try {
    // Check if the user is already registered
    const isRegistered = await sdk.auth.isRegistered(userId);
    
    if (!isRegistered) {
      // Register a new user
      await sdk.auth.register({
        profile: {
          id: userId,
          name: "New User"
        }
      });
      console.log("User successfully registered");
    }
    
    // Connect the user (log in)
    const session = await sdk.auth.connect(userId);
    console.log("User connected with address:", session.address);
    
    return session;
  } catch (error) {
    console.error("Error in authentication process:", error);
    throw error;
  }
}

Error Handling

All methods may throw errors that should be handled appropriately:

try {
  const result = await sdk.auth.connect("alice@example.com");
  // Process successful result
} catch (error) {
  if (error.code === "E_CANT_GET_CREDENTIAL") {
    console.error("Session expired or passkey not found");
    // Prompt user to connect again
  } else if (error.code === "E_ENVIRONMENT") {
    console.error("This method can only be called in a browser environment");
  } else {
    console.error("Authentication error:", error.message);
  }
}

Common error codes include:

  • E_CANT_CREATE_CREDENTIAL: Error creating WebAuthn credential

  • E_CANT_GET_CREDENTIAL: Error retrieving credential or wallet not found

  • E_ENVIRONMENT: Method called in an unsupported environment (e.g., outside the browser)