Skip to main content

Shib EOA SDK

Introduction

Shib EOA SDK offers a secure solution for users to sign into websites using Social logins like Google, Discord and Email and WalletConnect. In the case of Social login, it reconstruct a wallet with a Private/Public key pair in the background for downstream use cases like DIDs, Payments etc.

Check out the Web3Auth documentation to understand how wallet reconstruction happens.

Installation

Prerequisites

This SDK is designed to be used with Next.js (version 13 or higher). It can also be used with React-based frameworks capable of including API services, with some adaptations. Ensure your project meets these requirements before proceeding.

Before installing the SDK:

  1. Create an empty .npmignore file

  2. And then create a .npmrc file in the main folder of your project to include the token required for downloading the SDK. Include the following lines:

    @shibaone:registry=https://npm.pkg.github.com
    package-lock=false

    //npm.pkg.github.com/:_authToken=YOUR_TOKEN_HERE

Installing the SDK

Install the SDK from the command line:

yarn add @shibaone/shib-auth-sdk

or via package.json:

"@shibaone/shib-auth-sdk": "1.0.78"

Building

First Install Dependencies:

yarn

Then generate build:

yarn build
note

Please ensure you use yarn as your package manager. Using other package managers like npm or pnpm may lead to inconsistencies due to differences in how they resolve and manage dependencies.

Environment Configuration

The variable NEXT_PUBLIC_AUTH0_BASE_PATH is used to configure the base URL of the Auth0 service that the application will interact with for authentication purposes. Specifically, this variable defines the endpoint or domain where the Auth0 API is hosted, enabling the application to handle operations such as user login, token exchange, and fetching user information.

This variable is the only environment variable that you can configure inside your application. It is also optional. If it is not set, the library will pass it server-side using a cookie. However, if you prefer not to use cookies, you need to specify this environment variable in the .env file of your project.

The reason for this variable to be passed via a cookie is that it is already included in the configuration provided by the environment-specific mode option but in the client-side.

Each environment contains an Auth0.domain setting that you can use as reference for the enviroment variable.

NEXT_PUBLIC_AUTH0_BASE_PATH="AUTH0_BASE_PATH"

Usage

Here’s how you can get started with the SDK:

Basic Configuration

The SDK includes mandatory files to be included in your project in order to have everything working in the application:

Service Worker

The Service Worker is responsible for the management of the redirect by Auth0 and is used for social login via email.

The SDK provides the serviceworker folder, for simplicity, which can be downloaded from the SDK's repo. Copy and paste it into the public folder of your project.

globals.css

In your globals.css file, add the following imports:

@import '@shibaone/shibhubui/styles.css';
@import "@rainbow-me/rainbowkit/styles.css";

These imports include the styles for ShibHub UI components and RainbowKit.

taiwlind.config

Modify your tailwind.config.ts file to update the content paths and include the necessary presets:

import type { Config } from "tailwindcss";
import shibHubUiPreset from '@shibaone/shibhubui/tailwind.preset.js';

const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
'./node_modules/@shibaone/shibhubui/dist/**/*.js', // to add
'./node_modules/@shibaone/shib-auth-sdk/dist/**/*.js', // to add
],
theme: {
extend: {
colors: {
background: "var(--background)",
foreground: "var(--foreground)",
},
},
},
plugins: [],
presets: [
shibHubUiPreset, // to add
],
};
export default config;
note

If your project does not include Tailwind, please install it and use the configuration above. Learn how to add Tailwind to your project on their documentation.

Authorize page

The Authorize page is used for sending the email to the user and show the code for the login.

To generate this page, create authorize/page.tsx under the app folder:

authorize/page.tsx
'use client';
import React from 'react';
import { AuthorizePage } from '@shibaone/shib-auth-sdk';

export default function Authorize() {
const siteTitle = "Test App"
return (
<AuthorizePage
siteTitle={siteTitle}
/>
);
}

API routes

userinfo

Create userinfo/route.tsx under the app folder.

This file is used for getting the user info retrieved from Auth0.

You can configure the environment variable NEXT_PUBLIC_AUTH0_BASE_PATH to set the Auth0 URL. If not specified, it will be automatically retrieved from cookies.

userinfo/route.tsx
import { NextRequest, NextResponse } from 'next/server';
import { headers } from 'next/headers';
import { GetUserInfo } from '@shibaone/shib-auth-sdk';

export async function GET(req: NextRequest) {
const headers_instance = await headers();
const access_token = headers_instance.get('Authorization');
const cookies = req.headers.get('cookie');
const auth0Url = process.env.NEXT_PUBLIC_AUTH0_BASE_PATH ?? cookies
?.split('; ')
.find(cookie => cookie.startsWith('auth0Url='))
?.split('=')[1];

try {
if (!access_token) throw new Error('Access token not setted');
if (!auth0Url) throw new Error('Auth0 Url cookie not setted');
const response = await GetUserInfo(access_token, auth0Url);
return NextResponse.json(response, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json(error, { status: 500 });
}
}

Integrate the SDK Provider

Wrap your application with the SDK's provider component to enable its features. Pass in your desired configuration to this provider. You can find more information about the options here.

"use client"
import React from 'react';
import { Environments, ShibAuthSdk, IAuthOptions, shibariumChain } from '@shibaone/shib-auth-sdk';

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
useEffect(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/serviceworker/sw.js')
.then(registration => console.log('scope is: ', registration.scope));
}
}, []);

const networkOptions: IAuthOptions = {
GoogleProvider: undefined,
DiscordProvider: undefined,
Chains: [shibariumChain],
// If you use DEV enviroment and you don't have the project running in your local environment then use the TEST authenticator API URL
AuthenticatorApiUrl: "https://auth.shibinternal.com/api"
};

return (
<html lang="en">
<body>
<ShibAuthSdk mode={Environments.DEV} options={networkOptions}>
{ children }
</ShibAuthSdk>
</body>
</html>
);
}

Implementing a Login Button

Use the useShibAuth hook from the SDK for login functionality:

import React from 'react';
import { useShibAuth } from '@shibaone/shib-auth-sdk';

function LoginButton() {
const { openLoginModal } = useShibAuth();

return (
<button onClick={() => openLoginModal()}>Login</button>
);
}

export default LoginButton;

API Documentation

useShibAuth hook:

State Variables

user: User Represents the current authenticated user. This can be of type WAGMI or WEB3AUTH.. currentChain: IChain Represents the currently connected blockchain network. isConnected: boolean

web3auth Object

The web3auth object is only available if the user is of type WEB3AUTH. It contains various functions and properties specific to managing Web3Auth users.

web3auth Methods

configureConfirmations

Configure the confirmation methods that the wallet will use before every blockchain action that needs a confirmation by the user.

It will works only if the Web3AuthWalletConfirmationsEnabled option is enabled. Parameters:

parameterrequired/optionaltypedescription
actionsrequiredRecord<ConfirmationModalStates, (params?: any) => void>An object where each key corresponds to a ConfirmationModalStates, with each value being a callback function that accepts optional parameters.

Returns: void No return value.

setCurrentWallet

Sets the main or derived wallet for the Web3Auth user. Parameters:

parameterrequired/optionaltypedescription
idrequirednumberThe path index, 0 for the main and >1 for derived wallets.

Returns: Promise<void> No return value.

createDerivedWallet

Creates a new derived wallet for the Web3Auth user. Parameters:

parameterrequired/optionaltypedescription
nameoptionalsringThe name of the derived wallet.
Returns: Promise<void>

hasAuthenticator

Checks if the Web3Auth user has an authenticator set up. Parameters: None Returns: Promise<boolean> A promise that resolves to true if the user has an authenticator, false otherwise.

hasSeedPhrase

Checks if the Web3Auth user has a seed phrase set up. Parameters: None Returns: Promise<boolean> A promise that resolves to true if the user has a seed phrase, false otherwise.

hasPassword

Checks if the Web3Auth user has a password set up. Parameters: None Returns: Promise<boolean> A promise that resolves to true if the user has a password, false otherwise.

web3auth Objects

The modal object is responsible for showing and hiding the different modals related to the user's authentication and wallet management.

modal.openPrivateKeyModal

Opens the private key display modal for Web3Auth users. Parameters: None Returns: void Throws: Error if the user is not logged in. Error if the user type is WAGMI.

modal.closePrivateKeyModal

Closes the private key display modal if it's currently open. Parameters: None Returns: void

modal.setup Object

The setup object within modal contains functions for opening and closing modals related to initial user setup, including setting up passwords, authenticators, and seed phrases.

modal.setup Methods

modal.setup.openPasswordModal

Opens the password setup modal for Web3Auth users. Parameters: None Returns: void Throws: Error if the user is not logged in. Error if the user type is WAGMI. Error if the user already has a password.

modal.setup.openAuthenticatorModal

Opens the authenticator setup modal for Web3Auth users. Parameters: None Returns: void Throws: Error if the user is not logged in. Error if the user type is WAGMI. Error if the user already has an authenticator.

modal.setup.openSeedPhraseModal

Opens the seed phrase setup modal for Web3Auth users. Parameters: None Returns: void Throws: Error if the user is not logged in. Error if the user type is WAGMI.

modal.setup.closePasswordModal

Closes the password setup modal if it's currently open. Parameters: None Returns: void

modal.setup.closeAuthenticatorModal

Closes the authenticator setup modal if it's currently open. Parameters: None Returns: void

modal.setup.closeSeedPhraseModal

Closes the seed phrase setup modal if it's currently open. Parameters: None Returns: void

Methods

openLoginModal

Opens the login modal. Parameters:

parameterrequired/optionaltypedescription
emailoptionalstringAn optional email to prefill in the login form.
Throws: Error if the user is already logged in.

closeLoginModal

Closes the login modal if it's currently open. Returns: void

getEthersSigner

Returns an ethers.js signer for the current user. Returns: Promise<Signer> A promise that returns a Signer object of ethers.js. Throws: Error if the user is not logged in.

changeChain

Change the current blockchain network. Parameters

parameterrequired/optionaltypedescription
chainrequiredIChainThe chain to connect to.
Returns: Promise<void> No return value.
Throws: Error if user is not connected.

changeChainById

Change the current blockchain network by chain ID. Parameters:

parameterrequired/optionaltypedescription
chainIdrequirednumberThe chain ID to connect to.
Returns: Promise<void> No return value.
Throws: Error if user is not connected.

getProvider

Retrieves the provider for the current user. can be used by ethersjs BrowserProvider and web3js Web3 Returns: Promise<GetWalletClientReturnType | string | Eip1193Provider> A promise that resolves to the appropriate provider. GetWalletClientReturnType for Wagmi, Eip1193Provider for Web3Auth and string (the first configured blockchain RPC url) if the user is not connected.

Usage Example

import React from 'react';
import { BrowserProvider } from 'ethers';

export default function Component() {
const { getProvider } = useShibAuth();
const logProvider = async () => {
const shibAuthProvider = await getProvider();
const provider = new BrowserProvider(shibAuthProvider as any);
console.log("Provider:", provider)
}
return (<><button onClick={logProvider}></button></>);
}

logoutUser

Logs out the current user and resets the user and currentChain state. Returns: Promise<void> No return value. Throws: Error if the user is not logged in.

ShibAuthSdk Provider:

mode

Use this option to specify in which enviroment you are using the SDK. It provides already configured options for the SDK Can be: Enviroments.DEV Enviroments.TEST Enviroments.PROD

options

Provider Options (IAuthOptions)

These options are used to configure the behavior and capabilities of the ShibAuthProvider. Let's explore the real options that you should configure:

IsDecentralizedDisabled

Type: boolean Description: Allows the wagmi connection. Default: false

Chains

Type: IChain[] Description: An array of blockchain networks (IChain) that the application can connect to. Each IChain includes details like chain ID, name, RPC URLs etc.

LocalhostDevMode

Type: boolean Description: Enables development mode for Web3Auth when using localhost on port 3000.

WalletConnectors

Type: WalletConnector[] Description: An array of wallet connectors that the application supports. This includes options like MetaMask, Coinbase, Rainbow, and others.

Web3AuthWalletConfirmationsEnabled

Type: boolean Description: Enables or disables wallet confirmations within the Web3Auth provider.

AuthenticatorApiUrl

Type: string Description: API used to setup the Authenticator code as recovery of the account. You can find here the repository.

rainbowkitThemeConfig

Type: Theme Description: Customize the Rainbowkit modal. See documentation here

Simple Component Example

This component leverages the SDK to provide seamless Web3 authentication and blockchain interactions. Below is a comprehensive list of features:

Authentication

Login Modal: Opens a login modal for user authentication using openLoginModal(email: string). Logout: Logs the user out using logoutUser().

User Management

Check User Status: Access the logged-in user details using the user object. Determine Connection State: Check if the user is connected using isConnected.

Wallet Management

Get Wallet Signer: Retrieve the wallet signer with getEthersSigner(). Get Wallet Provider: Retrieve the provider instance using getProvider(). Get Balance: Fetch the balance of the user's wallet using the signer. Create Derived Wallet: Create a new derived wallet with web3auth.createDerivedWallet(). Set Current Wallet: Set the wallet by deterministic index using web3auth.setCurrentWallet(index: number).

Network Management

Change Network: Switch to a different network using changeChain(chain): Predefined chains include: shibariumChain sepoliaChain Get Current Chain: Access the current blockchain network via currentChain.

Web3Auth Features (User Type: WEB3AUTH)

Modals for Wallet Management: Open and manage modals: Show Private Key: web3auth.modals.openPrivateKeyModal() Password Setup: web3auth.modals.setup.openPasswordModal() Authenticator Setup: web3auth.modals.setup.openAuthenticatorModal() Seed Phrase Setup: web3auth.modals.setup.openSeedPhraseModal()

User Security Features: Check Authenticator Status: web3auth.hasAuthenticator() Critical Reset Account: web3auth.criticalResetAccount()

Configure Confirmations: Customize UI confirmations for blockchain actions using configureConfirmations(config: object).

Blockchain Interactions

Sign and Send Transactions: Sign messages: signMessage(message: string) Sign and send transactions using Web3.js: Basic transaction signing. Approval transactions via ERC20 contracts.

Code:

"use client";
import {
useShibAuth,
shibariumChain,
sepoliaChain,
UserType,
} from "@shibaone/shib-auth-sdk";
import Web3 from "web3";
import { useEffect, useState } from "react";

export default function Home() {
const {
user,
getEthersSigner,
openLoginModal,
logoutUser,
web3auth,
getProvider,
changeChain,
currentChain,
isConnected,
openModal,
configureConfirmations
} = useShibAuth();
const [detIndex, setDetIndex] = useState(0);

useEffect(() => {
console.log(`Connected: ${isConnected}\nUser: ${user}`)
}, [isConnected]);

return (
<div className="text-white">
<h1>User: {user && "User logged"}</h1> {/* Display user status */}
<h1>Chain: {currentChain && currentChain.name}</h1> {/* Display current chain name */}

{/* Login button */}
<button
className="bg-orange-500"
onClick={() => openLoginModal("test@shib.io")}
>
Login
</button>

{/* Logout button, only visible if user is connected */}
{isConnected && (
<button className="bg-gray-400 ml-2" onClick={() => logoutUser()}>
Logout
</button>
)}

{/* Display options for Web3Auth users only */}
{user && user.type === UserType.WEB3AUTH && (
<>
<br />
{/* Show Private Key */}
<button
className="border border-red-400"
onClick={() => web3auth.modals.openPrivateKeyModal()}
>
Show Private Key
</button>
<br />
{/* Setup Password */}
<button
className="border border-red-400"
onClick={() => web3auth.modals.setup.openPasswordModal()}
>
Setup Password
</button>
<br />
{/* Setup Authenticator */}
<button
className="border border-red-400"
onClick={() => web3auth.modals.setup.openAuthenticatorModal()}
>
Setup Authenticator
</button>
<br />
{/* Check if Authenticator is available */}
<button
className="border border-red-400"
onClick={async () => console.log(await web3auth.hasAuthenticator())}
>
has Authenticator
</button>
<br />
{/* Setup Seed Phrase */}
<button
className="border border-red-400"
onClick={() => web3auth.modals.setup.openSeedPhraseModal()}
>
Setup Seed Phrase
</button>
<br />
{/* Reset Account */}
<button
className="border border-red-400"
onClick={() => web3auth.criticalResetAccount()}
>
Reset Account
</button>
</>
)}
<br />

{/* Get Signer */}
<button
onClick={async () => console.log("Signer ", await getEthersSigner())}
>
Get Signer
</button>
<br />

{/* Get Signer Network */}
<button
onClick={async () => {
const signer = await getEthersSigner();
console.log("Signer network", await signer.provider!.getNetwork());
}}
>
Get Signer Network
</button>
<br />

{/* Get Balance */}
<button
onClick={async () => {
const signer = await getEthersSigner();
console.log("Signer network", await signer.provider.getBalance(signer.address));
}}
>
Get Balance
</button>
<br />

{/* Get Provider */}
<button
onClick={async () => console.log("Provider ", await getProvider())}
>
Get Provider
</button>
<br />

{/* Display user details */}
<button onClick={async () => console.log("USER ", user)}>Get User</button>
<br />

{/* Change network to Shibarium */}
<button onClick={async () => changeChain(shibariumChain)}>
Change network to shibarium
</button>
<br />

{/* Change network to Sepolia */}
<button onClick={async () => changeChain(sepoliaChain)}>
Change network to sepolia
</button>
<br />

{/* Create Derived Wallet */}
<button onClick={async () => await web3auth.createDerivedWallet()}>
Create Derived Wallet
</button>
<br />

{/* Deterministic Wallet Index Input */}
Deterministic index:
<input
type="text"
onChange={(e) => setDetIndex(parseInt(e.target.value))}
/>
<br />

{/* Set Current Wallet based on deterministic index */}
<button
onClick={async () => {
web3auth.setCurrentWallet(detIndex);
console.log(user);
}}
>
Set Current Wallet
</button>
<br />

{/* Configure custom UI for confirmations */}
<button
onClick={async () => {
configureConfirmations({
CONFIRM_SIGN_MESSAGE: (params?) =>
openModal("CONFIRM_SIGN_MESSAGE", params),
CONFIRM_SIGN_TRANSACTION: (params?) =>
openModal("CONFIRM_SIGN_TRANSACTION", params),
CONFIRM_APPROVAL: function (params?: any): void {
throw new Error("Function not implemented.");
},
CONFIRM_SEND_TX: function (params?: any): void {
throw new Error("Function not implemented.");
},
});
}}
>
Setup custom UI for confirmation
</button>
<br />

{/* Sign message 'ciao' */}
<button
onClick={async () => {
const signer = await getEthersSigner();
const sign = await signer?.signMessage("ciao");
console.log("Sign 'ciao': ", sign);
}}
>
Sign "ciao"
</button>
<br />

{/* Sign and send sample transaction, using web3js */}
<button
onClick={async () => {
const w3 = new Web3((await getProvider()) as any);
const tx = {
from: user?.address,
to: user?.address,
value: Web3.utils.toWei("0.0001"),
};
const sign = await w3.eth.signTransaction(tx, user!.address);
console.log("Sign sample tx: ", sign);
await w3.eth.sendSignedTransaction(sign.raw);
}}
>
Sign sample TX v2
</button>
<br />

{/* Send approval transaction using a contract, using web3js */}
<button
onClick={async () => {
const w3 = new Web3((await getProvider()) as any);
const tx = {
from: user?.address,
to: user?.address,
value: Web3.utils.toWei("0.0001"),
};
const contract = new w3.eth.Contract(
erc20ABI as any,
"0xcA94c8B16209CCBAfCFeab9D7649DdaEcD444007"
);
await contract.methods
.approve(user!.address, Web3.utils.toWei("0.0001"))
.send({ from: user!.address });
}}
>
Send Approval tx
</button>
<br />
<br />
</div>
);
}