Skip to main content

Create & Auth


Liquality Wallet API and SDK relies on Torus wallet tech for authentication. This significantly simplifies the onboarding experience and removes risk of key loss as users do not need to keep track of a seed phrase. Instead, authentication is handled by key shares that allow for easy recoverability without compromising security.

Overview

The keys are managed by creating shares of the private key via Shamir Secret Sharing.

ShareNumberOne Could be stored on the user's device, similarly to how you usually can store a private key or seed phrase on a hardware device.

ShareNumberTwo could be split across the Torus Tech Network, only accessed by a OAuth provider login that the user owns. This could be Google SSO, or any of the other login providers that are currently supported (Facebook, Twitch, Discord)

ShareNumberThree This share is a recovery share, which can be accessed through a users set password


Liquality SDK provides different levels of support for the auth and creation.

  • Full flow is provided by a UI component that can be embedded and you get login flow + full recovery.

  • Programmatic access: easy to use API for login and recovery but the integration with UI happens by the developer. This gives flexibility for any use case.


Recovery

Users need to prove ownership of ⅔ shares in order to retrieve and recover their private key.

That means if you choose to split your shares between Google SSO, device storage and password, you can recover your account using google SSO + the password for example.


Programmatic Authorization

Create a wallet

In order to create a wallet or do wallet interactions, you first have to initiate the tKey instance.

This is done by calling:

import { AuthService, tryRegisterSW } from "@liquality/wallet-sdk";

// Register a service worker hosted at the root of the site using the default scope.
const registration = tryRegisterSW("/serviceworker/sw.js");

const tKey = AuthService.init(directParams);

The init() function takes an object that we call directParams and it has the following object properties:

NameTypeDescription
baseUrlstringthe path to the serviceworker that is being served
enableLoggingbooleandecides if logging should be enabled
networkUrlstringrpcUrl to the network you want to connect to
networkstringtorusNetwork, could be mainnet or testnet

Example:

const directParams = {
baseUrl: `http://localhost:3005/serviceworker`,
enableLogging: true,
networkUrl: "https://goerli.infura.io/v3/a8684b771e9e4997a567bbd7189e0b27",
network: "testnet" as any,
};
Supported Networks

Liquality SDK create & auth functions currently supports all Ethereum networks, Binance Smart Chain, Polygon (Matic), ReefChain and xDai.

Then you can trigger a wallet creation with google SSO. This is done by calling the

const wallet = await AuthService.createWallet(tKey, verifierMap);

Where tKey is the variable that you got from the init() function and the verifierMap is an object with the properties:

const verifierMap: Record<string, any> = {
google: {
name: "Google",
typeOfLogin: "google",
clientId:
"852640103435-0qhvrgpkm66c9hu0co6edkhao3hrjlv3.apps.googleusercontent.com",
verifier: "liquality-google-testnet",
},
};
NameTypeDescription
namestringname of type of SSO login
typeOfLoginstringtype of SSO login
clientIdstringclient ID that is taken from the SSO, developers portal
verifierstringthe verifier name from the SSO developers portal

A clientID and verifier can be created on the Google developers portal. For google SSO with gmail, you can follow the steps to create authorization details: https://developers.google.com/identity/sign-in/web/sign-in

Set a password share

After you created your wallet, you can set a password share for the user.

Parameters:

NameTypeDescription
tKeyThresholdkeytKey instance from the init()
passwordstringthe password the user inputs
let response = await AuthService.generateNewShareWithPassword(
tKey: ThresholdKey,
password: string
);

Login and unlock wallet

Unlock wallet with single-sign-on This function uses 2 of the shares (the webstorage share that is stored on the browser side) and the share stored on the service provider to log in and unlock your wallet.

const loginResponse = await loginUsingSSO(tKey: ThresholdKey, verifierMap: Record<string, any>)

It expects the tKey that is initilized from the init() function and the verifierMap described previously.

React Example

Create wallet & sign in

import * as React from "react";
import { useState, useEffect } from "react";
import { AuthService, tryRegisterSW } from "@liquality/wallet-sdk";
import { DirectParams } from "sdk/src/types";

type Props = {
directParams: DirectParams,
verifierMap: Record<string, any>,
};

export const CreateWallet: React.FC<Props> = (props) => {
const { directParams, verifierMap } = props;
const [tKey, setTKey] = useState < any > {};
const [loginResponse, setLoginResponse] = useState < any > {};
const [password, setPassword] = useState < string > "";
const [errorMsg, setErrorMsg] = useState < string > "";
const [passwordResponse, setPasswordResponse] = useState < string > "";
const [newPasswordShare, setNewPasswordShare] = useState < any > {};

useEffect(() => {
const init = async () => {
tryRegisterSW("/serviceworker/sw.js");
const tKeyResponse = await AuthService.init(directParams);
setTKey(tKeyResponse);
};

init();
}, [loginResponse, passwordResponse]);

const createNewWallet = async () => {
const response = await AuthService.createWallet(tKey, verifierMap);
setLoginResponse(response);
};

const generatePassword = async (password: string) => {
let response = await AuthService.generateNewShareWithPassword(
loginResponse.tKey,
password
);
setNewPasswordShare(response.result);
response.msg.startsWith("Error")
? setErrorMsg(response.msg)
: setPasswordResponse(response.msg);
};

const _renderPasswordInput = () => {
return (
<div>
Set password minimum 10 characters:
<input
type="password"
placeholder="Address"
value={password}
onChange={(e) => {
setPassword(e.target.value);
}}
/>
<button onClick={() => generatePassword(password)}>Set password</button>
<br></br>
{errorMsg ? <p style={{ color: "red" }}> {errorMsg}</p> : null}
{passwordResponse.startsWith("Error") ? (
<p style={{ color: "red" }}> {passwordResponse}</p>
) : (
<p style={{ color: "green" }}>{passwordResponse}</p>
)}
</div>
);
};

const _renderCreatedWalletDetails = () => {
return (
<div>
<h3 style={{ color: "green" }}>
Your wallet was created successfully!
</h3>
<p>
<b>Public Address:</b> <br></br>
{loginResponse.loginResponse?.publicAddress}
</p>
<p>
<b>Private Key:</b> <br></br>
{loginResponse.loginResponse?.privateKey}
</p>
<p>
<b>User email:</b> <br></br> {loginResponse.loginResponse?.userInfo?.email}
</p>
</div>
);
};

return (
<div style={{ border: "1px solid black", padding: 10 }}>
<h3>Liquality & tKey Create Wallet</h3>
<button onClick={createNewWallet}>Create Wallet</button>
{loginResponse.loginResponse ? _renderCreatedWalletDetails() : null}
{loginResponse.loginResponse ? _renderPasswordInput() : null}
</div>
);
};

UI Component Authorization

Coming soon...