Updated main provider to include Chronicle
This commit is contained in:
		
							
								
								
									
										66
									
								
								example/google-auth/src/pages/_app.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								example/google-auth/src/pages/_app.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
import { AppProps } from 'next/app';
 | 
			
		||||
import { WagmiConfig, createClient, configureChains } from 'wagmi';
 | 
			
		||||
import { publicProvider } from 'wagmi/providers/public';
 | 
			
		||||
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect';
 | 
			
		||||
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
 | 
			
		||||
import { Chain } from 'wagmi/chains';
 | 
			
		||||
 | 
			
		||||
const chronicleChain: Chain = {
 | 
			
		||||
  id: 175177,
 | 
			
		||||
  name: 'Chronicle',
 | 
			
		||||
  network: 'chronicle',
 | 
			
		||||
 | 
			
		||||
  nativeCurrency: {
 | 
			
		||||
    decimals: 18,
 | 
			
		||||
    name: 'Chronicle - Lit Protocol Testnet',
 | 
			
		||||
    symbol: 'LIT',
 | 
			
		||||
  },
 | 
			
		||||
  rpcUrls: {
 | 
			
		||||
    default: {
 | 
			
		||||
      http: ['https://chain-rpc.litprotocol.com/http'],
 | 
			
		||||
    },
 | 
			
		||||
    public: {
 | 
			
		||||
      http: ['https://chain-rpc.litprotocol.com/http'],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  blockExplorers: {
 | 
			
		||||
    default: {
 | 
			
		||||
      name: 'Chronicle - Lit Protocol Testnet',
 | 
			
		||||
      url: 'https://chain.litprotocol.com',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  testnet: true,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const { provider, chains } = configureChains(
 | 
			
		||||
  [chronicleChain],
 | 
			
		||||
  [
 | 
			
		||||
    jsonRpcProvider({
 | 
			
		||||
      rpc: chain => ({ http: chain.rpcUrls.default.http[0] }),
 | 
			
		||||
    }),
 | 
			
		||||
    publicProvider(),
 | 
			
		||||
  ]
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const client = createClient({
 | 
			
		||||
  autoConnect: true,
 | 
			
		||||
  connectors: [
 | 
			
		||||
 | 
			
		||||
    new WalletConnectConnector({
 | 
			
		||||
      chains,
 | 
			
		||||
      options: {
 | 
			
		||||
        projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID,
 | 
			
		||||
      },
 | 
			
		||||
    }),
 | 
			
		||||
  ],
 | 
			
		||||
  provider,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function MyApp({ Component, pageProps }: AppProps) {
 | 
			
		||||
  return (
 | 
			
		||||
    <WagmiConfig client={client}>
 | 
			
		||||
      <Component {...pageProps} />
 | 
			
		||||
    </WagmiConfig>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								example/google-auth/src/pages/_document.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								example/google-auth/src/pages/_document.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import { Html, Head, Main, NextScript } from 'next/document';
 | 
			
		||||
 | 
			
		||||
export default function Document() {
 | 
			
		||||
  return (
 | 
			
		||||
    <Html lang="en">
 | 
			
		||||
      <Head />
 | 
			
		||||
      <body>
 | 
			
		||||
        <Main />
 | 
			
		||||
        <NextScript />
 | 
			
		||||
      </body>
 | 
			
		||||
    </Html>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										614
									
								
								example/google-auth/src/pages/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										614
									
								
								example/google-auth/src/pages/index.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,614 @@
 | 
			
		||||
import Head from 'next/head';
 | 
			
		||||
import { useCallback, useEffect, useState } from 'react';
 | 
			
		||||
import { LitNodeClient } from '@lit-protocol/lit-node-client';
 | 
			
		||||
import {
 | 
			
		||||
  LitAuthClient,
 | 
			
		||||
  BaseProvider,
 | 
			
		||||
  GoogleProvider,
 | 
			
		||||
  EthWalletProvider,
 | 
			
		||||
  WebAuthnProvider,
 | 
			
		||||
  isSignInRedirect,
 | 
			
		||||
  getProviderFromUrl,
 | 
			
		||||
} from '@lit-protocol/lit-auth-client';
 | 
			
		||||
import { IRelayPKP, AuthMethod, SessionSigs } from '@lit-protocol/types';
 | 
			
		||||
import { ProviderType } from '@lit-protocol/constants';
 | 
			
		||||
import { ethers } from 'ethers';
 | 
			
		||||
import { useRouter } from 'next/router';
 | 
			
		||||
import { useConnect, useAccount, useDisconnect, Connector } from 'wagmi';
 | 
			
		||||
import {LitAccessControlConditionResource, LitAbility} from '@lit-protocol/auth-helpers';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Local dev only: When using npm link, need to update encryption pkg to handle possible ipfs client init error
 | 
			
		||||
// let ipfsClient = null;
 | 
			
		||||
// try {
 | 
			
		||||
//   ipfsClient = require("ipfs-http-client");
 | 
			
		||||
// } catch {}
 | 
			
		||||
 | 
			
		||||
enum Views {
 | 
			
		||||
  SIGN_IN = 'sign_in',
 | 
			
		||||
  HANDLE_REDIRECT = 'handle_redirect',
 | 
			
		||||
  REQUEST_AUTHSIG = 'request_authsig',
 | 
			
		||||
  REGISTERING = 'webauthn_registering',
 | 
			
		||||
  REGISTERED = 'webauthn_registered',
 | 
			
		||||
  AUTHENTICATING = 'webauthn_authenticating',
 | 
			
		||||
  FETCHING = 'fetching',
 | 
			
		||||
  FETCHED = 'fetched',
 | 
			
		||||
  MINTING = 'minting',
 | 
			
		||||
  MINTED = 'minted',
 | 
			
		||||
  CREATING_SESSION = 'creating_session',
 | 
			
		||||
  SESSION_CREATED = 'session_created',
 | 
			
		||||
  ERROR = 'error',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function Dashboard() {
 | 
			
		||||
  const redirectUri = 'http://localhost:3000';
 | 
			
		||||
 | 
			
		||||
  const router = useRouter();
 | 
			
		||||
 | 
			
		||||
  const [view, setView] = useState<Views>(Views.SIGN_IN);
 | 
			
		||||
  const [error, setError] = useState<any>();
 | 
			
		||||
 | 
			
		||||
  const [litAuthClient, setLitAuthClient] = useState<LitAuthClient>();
 | 
			
		||||
  const [litNodeClient, setLitNodeClient] = useState<LitNodeClient>();
 | 
			
		||||
  const [currentProviderType, setCurrentProviderType] =
 | 
			
		||||
    useState<ProviderType>();
 | 
			
		||||
  const [authMethod, setAuthMethod] = useState<AuthMethod>();
 | 
			
		||||
  const [pkps, setPKPs] = useState<IRelayPKP[]>([]);
 | 
			
		||||
  const [currentPKP, setCurrentPKP] = useState<IRelayPKP>();
 | 
			
		||||
  const [sessionSigs, setSessionSigs] = useState<SessionSigs>();
 | 
			
		||||
 | 
			
		||||
  const [message, setMessage] = useState<string>('Free the web!');
 | 
			
		||||
  const [signature, setSignature] = useState<string>();
 | 
			
		||||
  const [recoveredAddress, setRecoveredAddress] = useState<string>();
 | 
			
		||||
  const [verified, setVerified] = useState<boolean>(false);
 | 
			
		||||
 | 
			
		||||
  // Use wagmi to connect one's eth wallet
 | 
			
		||||
  const { connectAsync, connectors } = useConnect({
 | 
			
		||||
    onError(error) {
 | 
			
		||||
      console.error(error);
 | 
			
		||||
      setError(error);
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
  const { isConnected, connector, address } = useAccount();
 | 
			
		||||
  const { disconnectAsync } = useDisconnect();
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Use wagmi to connect one's eth wallet and then request a signature from one's wallet
 | 
			
		||||
   */
 | 
			
		||||
  async function handleConnectWallet(c: any) {
 | 
			
		||||
    const { account, chain, connector } = await connectAsync(c);
 | 
			
		||||
    try {
 | 
			
		||||
      await authWithWallet(account, connector);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Begin auth flow with Google
 | 
			
		||||
   */
 | 
			
		||||
  async function authWithGoogle() {
 | 
			
		||||
    setCurrentProviderType(ProviderType.Google);
 | 
			
		||||
    const provider = litAuthClient.initProvider<GoogleProvider>(
 | 
			
		||||
      ProviderType.Google
 | 
			
		||||
    );
 | 
			
		||||
    await provider.signIn();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Request a signature from one's wallet
 | 
			
		||||
   */
 | 
			
		||||
  async function authWithWallet(address: string, connector: Connector) {
 | 
			
		||||
    setView(Views.REQUEST_AUTHSIG);
 | 
			
		||||
 | 
			
		||||
    // Create a function to handle signing messages
 | 
			
		||||
    const signer = await connector.getSigner();
 | 
			
		||||
    const signAuthSig = async (message: string) => {
 | 
			
		||||
      const sig = await signer.signMessage(message);
 | 
			
		||||
      return sig;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Get auth sig
 | 
			
		||||
    const provider = litAuthClient.getProvider(ProviderType.EthWallet);
 | 
			
		||||
    const authMethod = await provider.authenticate({
 | 
			
		||||
      address,
 | 
			
		||||
      signMessage: signAuthSig,
 | 
			
		||||
    });
 | 
			
		||||
    setCurrentProviderType(ProviderType.EthWallet);
 | 
			
		||||
    setAuthMethod(authMethod);
 | 
			
		||||
 | 
			
		||||
    // Fetch PKPs associated with eth wallet account
 | 
			
		||||
    setView(Views.FETCHING);
 | 
			
		||||
    const pkps: IRelayPKP[] = await provider.fetchPKPsThroughRelayer(
 | 
			
		||||
      authMethod
 | 
			
		||||
    );
 | 
			
		||||
    if (pkps.length > 0) {
 | 
			
		||||
      setPKPs(pkps);
 | 
			
		||||
    }
 | 
			
		||||
    setView(Views.FETCHED);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function registerWithWebAuthn() {
 | 
			
		||||
    setView(Views.REGISTERING);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Register new PKP
 | 
			
		||||
      const provider = litAuthClient.getProvider(
 | 
			
		||||
        ProviderType.WebAuthn
 | 
			
		||||
      ) as WebAuthnProvider;
 | 
			
		||||
      setCurrentProviderType(ProviderType.WebAuthn);
 | 
			
		||||
      const options = await provider.register();
 | 
			
		||||
 | 
			
		||||
      // Verify registration and mint PKP through relayer
 | 
			
		||||
      const txHash = await provider.verifyAndMintPKPThroughRelayer(options);
 | 
			
		||||
      setView(Views.MINTING);
 | 
			
		||||
      const response = await provider.relay.pollRequestUntilTerminalState(
 | 
			
		||||
        txHash
 | 
			
		||||
      );
 | 
			
		||||
      if (response.status !== 'Succeeded') {
 | 
			
		||||
        throw new Error('Minting failed');
 | 
			
		||||
      }
 | 
			
		||||
      const newPKP: IRelayPKP = {
 | 
			
		||||
        tokenId: response.pkpTokenId!,
 | 
			
		||||
        publicKey: response.pkpPublicKey!,
 | 
			
		||||
        ethAddress: response.pkpEthAddress!,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // Add new PKP to list of PKPs
 | 
			
		||||
      const morePKPs: IRelayPKP[] = [...pkps, newPKP];
 | 
			
		||||
      setCurrentPKP(newPKP);
 | 
			
		||||
      setPKPs(morePKPs);
 | 
			
		||||
 | 
			
		||||
      setView(Views.REGISTERED);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function authenticateWithWebAuthn() {
 | 
			
		||||
    setView(Views.AUTHENTICATING);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const provider = litAuthClient.getProvider(
 | 
			
		||||
        ProviderType.WebAuthn
 | 
			
		||||
      ) as WebAuthnProvider;
 | 
			
		||||
      const authMethod = await provider.authenticate();
 | 
			
		||||
      setAuthMethod(authMethod);
 | 
			
		||||
 | 
			
		||||
      // Authenticate with a WebAuthn credential and create session sigs with authentication data
 | 
			
		||||
      setView(Views.CREATING_SESSION);
 | 
			
		||||
 | 
			
		||||
      const litResource = new LitAccessControlConditionResource('*');
 | 
			
		||||
      const sessionSigs = await provider.getSessionSigs({
 | 
			
		||||
        pkpPublicKey: currentPKP.publicKey,
 | 
			
		||||
        authMethod,
 | 
			
		||||
        sessionSigsParams: {
 | 
			
		||||
          chain: 'ethereum',
 | 
			
		||||
          resourceAbilityRequests: [{
 | 
			
		||||
              resource: litResource,
 | 
			
		||||
              ability: LitAbility.PKPSigning
 | 
			
		||||
          }],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      setSessionSigs(sessionSigs);
 | 
			
		||||
 | 
			
		||||
      setView(Views.SESSION_CREATED);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setAuthMethod(null);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  /**
 | 
			
		||||
   * Handle redirect from Lit login server
 | 
			
		||||
   */
 | 
			
		||||
  const handleRedirect = useCallback(
 | 
			
		||||
    async (providerName: string) => {
 | 
			
		||||
      setView(Views.HANDLE_REDIRECT);
 | 
			
		||||
      try {
 | 
			
		||||
        // Get relevant provider
 | 
			
		||||
        let provider: BaseProvider;
 | 
			
		||||
        if (providerName === ProviderType.Google) {
 | 
			
		||||
          provider = litAuthClient.getProvider(ProviderType.Google);
 | 
			
		||||
        } 
 | 
			
		||||
        setCurrentProviderType(providerName as ProviderType);
 | 
			
		||||
 | 
			
		||||
        // Get auth method object that has the OAuth token from redirect callback
 | 
			
		||||
        const authMethod: AuthMethod = await provider.authenticate();
 | 
			
		||||
        setAuthMethod(authMethod);
 | 
			
		||||
 | 
			
		||||
        // Fetch PKPs associated with social account
 | 
			
		||||
        setView(Views.FETCHING);
 | 
			
		||||
        const pkps: IRelayPKP[] = await provider.fetchPKPsThroughRelayer(
 | 
			
		||||
          authMethod
 | 
			
		||||
        );
 | 
			
		||||
        if (pkps.length > 0) {
 | 
			
		||||
          setPKPs(pkps);
 | 
			
		||||
        }
 | 
			
		||||
        setView(Views.FETCHED);
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
        setError(err);
 | 
			
		||||
        setView(Views.ERROR);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Clear url params once we have the OAuth token
 | 
			
		||||
      // Be sure to use the redirect uri route
 | 
			
		||||
      router.replace(window.location.pathname, undefined, { shallow: true });
 | 
			
		||||
    },
 | 
			
		||||
    [litAuthClient, router]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Mint a new PKP for current auth method
 | 
			
		||||
   */
 | 
			
		||||
  async function mint() {
 | 
			
		||||
    setView(Views.MINTING);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      // Mint new PKP
 | 
			
		||||
      const provider = litAuthClient.getProvider(currentProviderType);
 | 
			
		||||
      const txHash: string = await provider.mintPKPThroughRelayer(authMethod);
 | 
			
		||||
      const response = await provider.relay.pollRequestUntilTerminalState(
 | 
			
		||||
        txHash
 | 
			
		||||
      );
 | 
			
		||||
      if (response.status !== 'Succeeded') {
 | 
			
		||||
        throw new Error('Minting failed');
 | 
			
		||||
      }
 | 
			
		||||
      const newPKP: IRelayPKP = {
 | 
			
		||||
        tokenId: response.pkpTokenId,
 | 
			
		||||
        publicKey: response.pkpPublicKey,
 | 
			
		||||
        ethAddress: response.pkpEthAddress,
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // Add new PKP to list of PKPs
 | 
			
		||||
      const morePKPs: IRelayPKP[] = [...pkps, newPKP];
 | 
			
		||||
      setPKPs(morePKPs);
 | 
			
		||||
 | 
			
		||||
      setView(Views.MINTED);
 | 
			
		||||
      setView(Views.CREATING_SESSION);
 | 
			
		||||
 | 
			
		||||
      // Get session sigs for new PKP
 | 
			
		||||
      await createSession(newPKP);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate session sigs for current PKP and auth method
 | 
			
		||||
   */
 | 
			
		||||
  async function createSession(pkp: IRelayPKP) {
 | 
			
		||||
    setView(Views.CREATING_SESSION);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const litResource = new LitAccessControlConditionResource('*');
 | 
			
		||||
      // Get session signatures
 | 
			
		||||
      const provider = litAuthClient.getProvider(currentProviderType);
 | 
			
		||||
      const sessionSigs = await provider.getSessionSigs({
 | 
			
		||||
        pkpPublicKey: pkp.publicKey,
 | 
			
		||||
        authMethod,
 | 
			
		||||
        sessionSigsParams: {
 | 
			
		||||
          chain: 'ethereum',
 | 
			
		||||
          resourceAbilityRequests: [{
 | 
			
		||||
              resource: litResource,
 | 
			
		||||
              ability: LitAbility.PKPSigning
 | 
			
		||||
          }],
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      setCurrentPKP(pkp);
 | 
			
		||||
      setSessionSigs(sessionSigs);
 | 
			
		||||
 | 
			
		||||
      setView(Views.SESSION_CREATED);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sign a message with current PKP
 | 
			
		||||
   */
 | 
			
		||||
  async function signMessageWithPKP() {
 | 
			
		||||
    try {
 | 
			
		||||
      const toSign = ethers.utils.arrayify(ethers.utils.hashMessage(message));
 | 
			
		||||
      const litActionCode = `
 | 
			
		||||
        const go = async () => {
 | 
			
		||||
          // this requests a signature share from the Lit Node
 | 
			
		||||
          // the signature share will be automatically returned in the response from the node
 | 
			
		||||
          // and combined into a full signature by the LitJsSdk for you to use on the client
 | 
			
		||||
          // all the params (toSign, publicKey, sigName) are passed in from the LitJsSdk.executeJs() function
 | 
			
		||||
          const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName });
 | 
			
		||||
        };
 | 
			
		||||
        go();
 | 
			
		||||
      `;
 | 
			
		||||
      // Sign message
 | 
			
		||||
      // @ts-ignore - complains about no authSig, but we don't need one for this action
 | 
			
		||||
      const results = await litNodeClient.executeJs({
 | 
			
		||||
        code: litActionCode,
 | 
			
		||||
        sessionSigs: sessionSigs,
 | 
			
		||||
        jsParams: {
 | 
			
		||||
          toSign: toSign,
 | 
			
		||||
          publicKey: currentPKP.publicKey,
 | 
			
		||||
          sigName: 'sig1',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
      // Get signature
 | 
			
		||||
      const result = results.signatures['sig1'];
 | 
			
		||||
      const signature = ethers.utils.joinSignature({
 | 
			
		||||
        r: '0x' + result.r,
 | 
			
		||||
        s: '0x' + result.s,
 | 
			
		||||
        v: result.recid,
 | 
			
		||||
      });
 | 
			
		||||
      setSignature(signature);
 | 
			
		||||
 | 
			
		||||
      // Get the address associated with the signature created by signing the message
 | 
			
		||||
      const recoveredAddr = ethers.utils.verifyMessage(message, signature);
 | 
			
		||||
      setRecoveredAddress(recoveredAddr);
 | 
			
		||||
      // Check if the address associated with the signature is the same as the current PKP
 | 
			
		||||
      const verified =
 | 
			
		||||
        currentPKP.ethAddress.toLowerCase() === recoveredAddr.toLowerCase();
 | 
			
		||||
      setVerified(verified);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(err);
 | 
			
		||||
      setError(err);
 | 
			
		||||
      setView(Views.ERROR);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize LitNodeClient and LitAuthClient
 | 
			
		||||
     */
 | 
			
		||||
    async function initClients() {
 | 
			
		||||
      try {
 | 
			
		||||
        // Set up LitNodeClient and connect to Lit nodes
 | 
			
		||||
        const litNodeClient = new LitNodeClient({
 | 
			
		||||
          litNetwork: 'serrano',
 | 
			
		||||
          debug: false,
 | 
			
		||||
        });
 | 
			
		||||
        await litNodeClient.connect();
 | 
			
		||||
        setLitNodeClient(litNodeClient);
 | 
			
		||||
 | 
			
		||||
        // Set up LitAuthClient
 | 
			
		||||
        const litAuthClient = new LitAuthClient({
 | 
			
		||||
          litRelayConfig: {
 | 
			
		||||
            relayApiKey: 'test-api-key',
 | 
			
		||||
          },
 | 
			
		||||
          litNodeClient,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Initialize providers
 | 
			
		||||
        litAuthClient.initProvider<GoogleProvider>(ProviderType.Google);
 | 
			
		||||
        litAuthClient.initProvider<EthWalletProvider>(ProviderType.EthWallet);
 | 
			
		||||
        litAuthClient.initProvider<WebAuthnProvider>(ProviderType.WebAuthn);
 | 
			
		||||
 | 
			
		||||
        setLitAuthClient(litAuthClient);
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
        setError(err);
 | 
			
		||||
        setView(Views.ERROR);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!litNodeClient) {
 | 
			
		||||
      initClients();
 | 
			
		||||
    }
 | 
			
		||||
  }, [litNodeClient]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    // Check if app has been redirected from Lit login server
 | 
			
		||||
    if (litAuthClient && !authMethod && isSignInRedirect(redirectUri)) {
 | 
			
		||||
      const providerName = getProviderFromUrl();
 | 
			
		||||
      handleRedirect(providerName);
 | 
			
		||||
    }
 | 
			
		||||
  }, [litAuthClient, handleRedirect, authMethod]);
 | 
			
		||||
 | 
			
		||||
  if (!litNodeClient) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <Head>
 | 
			
		||||
        <title>Lit Auth Client</title>
 | 
			
		||||
        <meta
 | 
			
		||||
          name="description"
 | 
			
		||||
          content="Create a PKP with just a Google account"
 | 
			
		||||
        />
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
			
		||||
        <link rel="icon" href="/favicon.ico" />
 | 
			
		||||
      </Head>
 | 
			
		||||
      <main>
 | 
			
		||||
        {view === Views.ERROR && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Error</h1>
 | 
			
		||||
            <p>{error.message}</p>
 | 
			
		||||
            <button
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                if (sessionSigs) {
 | 
			
		||||
                  setView(Views.SESSION_CREATED);
 | 
			
		||||
                } else {
 | 
			
		||||
                  if (authMethod) {
 | 
			
		||||
                    setView(Views.FETCHED);
 | 
			
		||||
                  } else {
 | 
			
		||||
                    setView(Views.SIGN_IN);
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
                setError(null);
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              Got it
 | 
			
		||||
            </button>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.SIGN_IN && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Sign in with Lit</h1>
 | 
			
		||||
            {/* Since eth wallet is connected, prompt user to sign a message or disconnect their wallet */}
 | 
			
		||||
            <>
 | 
			
		||||
              {isConnected ? (
 | 
			
		||||
                <>
 | 
			
		||||
                  <button
 | 
			
		||||
                    disabled={!connector.ready}
 | 
			
		||||
                    key={connector.id}
 | 
			
		||||
                    onClick={async () => {
 | 
			
		||||
                      setError(null);
 | 
			
		||||
                      await authWithWallet(address, connector);
 | 
			
		||||
                    }}
 | 
			
		||||
                  >
 | 
			
		||||
                    Continue with {connector.name}
 | 
			
		||||
                  </button>
 | 
			
		||||
                  <button
 | 
			
		||||
                    onClick={async () => {
 | 
			
		||||
                      setError(null);
 | 
			
		||||
                      await disconnectAsync();
 | 
			
		||||
                    }}
 | 
			
		||||
                  >
 | 
			
		||||
                    Disconnect wallet
 | 
			
		||||
                  </button>
 | 
			
		||||
                </>
 | 
			
		||||
              ) : (
 | 
			
		||||
                <>
 | 
			
		||||
                  {/* If eth wallet is not connected, show all login options */}
 | 
			
		||||
                  <button onClick={authWithGoogle}>Google</button>
 | 
			
		||||
                  {connectors.map(connector => (
 | 
			
		||||
                    <button
 | 
			
		||||
                      disabled={!connector.ready}
 | 
			
		||||
                      key={connector.id}
 | 
			
		||||
                      onClick={async () => {
 | 
			
		||||
                        setError(null);
 | 
			
		||||
                        await handleConnectWallet({ connector });
 | 
			
		||||
                      }}
 | 
			
		||||
                    >
 | 
			
		||||
                      {connector.name}
 | 
			
		||||
                    </button>
 | 
			
		||||
                  ))}
 | 
			
		||||
                  <button onClick={registerWithWebAuthn}>
 | 
			
		||||
                    Register with WebAuthn
 | 
			
		||||
                  </button>
 | 
			
		||||
                </>
 | 
			
		||||
              )}
 | 
			
		||||
            </>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.HANDLE_REDIRECT && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Verifying your identity...</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.REQUEST_AUTHSIG && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Check your wallet</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.REGISTERING && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Register your passkey</h1>
 | 
			
		||||
            <p>Follow your browser's prompts to create a passkey.</p>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.REGISTERED && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Minted!</h1>
 | 
			
		||||
            <p>
 | 
			
		||||
              Authenticate with your newly registered passkey. Continue when
 | 
			
		||||
              you're ready.
 | 
			
		||||
            </p>
 | 
			
		||||
            <button onClick={authenticateWithWebAuthn}>Continue</button>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.AUTHENTICATING && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Authenticate with your passkey</h1>
 | 
			
		||||
            <p>Follow your browser's prompts to create a passkey.</p>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.FETCHING && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Fetching your PKPs...</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.FETCHED && (
 | 
			
		||||
          <>
 | 
			
		||||
            {pkps.length > 0 ? (
 | 
			
		||||
              <>
 | 
			
		||||
                <h1>Select a PKP to continue</h1>
 | 
			
		||||
                {/* Select a PKP to create session sigs for */}
 | 
			
		||||
                <div>
 | 
			
		||||
                  {pkps.map(pkp => (
 | 
			
		||||
                    <button
 | 
			
		||||
                      key={pkp.ethAddress}
 | 
			
		||||
                      onClick={async () => await createSession(pkp)}
 | 
			
		||||
                    >
 | 
			
		||||
                      {pkp.ethAddress}
 | 
			
		||||
                    </button>
 | 
			
		||||
                  ))}
 | 
			
		||||
                </div>
 | 
			
		||||
                <hr></hr>
 | 
			
		||||
                {/* Or mint another PKP */}
 | 
			
		||||
                <p>or mint another one:</p>
 | 
			
		||||
                <button onClick={mint}>Mint another PKP</button>
 | 
			
		||||
              </>
 | 
			
		||||
            ) : (
 | 
			
		||||
              <>
 | 
			
		||||
                <h1>Mint a PKP to continue</h1>
 | 
			
		||||
                <button onClick={mint}>Mint a PKP</button>
 | 
			
		||||
              </>
 | 
			
		||||
            )}
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.MINTING && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Minting your PKP...</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.MINTED && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Minted!</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.CREATING_SESSION && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Saving your session...</h1>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
        {view === Views.SESSION_CREATED && (
 | 
			
		||||
          <>
 | 
			
		||||
            <h1>Ready for the open web</h1>
 | 
			
		||||
            <div>
 | 
			
		||||
              <p>Check out your PKP:</p>
 | 
			
		||||
              <p>{currentPKP.ethAddress}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <hr></hr>
 | 
			
		||||
            <div>
 | 
			
		||||
              <p>Sign this message with your PKP:</p>
 | 
			
		||||
              <p>{message}</p>
 | 
			
		||||
              <button onClick={signMessageWithPKP}>Sign message</button>
 | 
			
		||||
 | 
			
		||||
              {signature && (
 | 
			
		||||
                <>
 | 
			
		||||
                  <h3>Your signature:</h3>
 | 
			
		||||
                  <p>{signature}</p>
 | 
			
		||||
                  <h3>Recovered address:</h3>
 | 
			
		||||
                  <p>{recoveredAddress}</p>
 | 
			
		||||
                  <h3>Verified:</h3>
 | 
			
		||||
                  <p>{verified ? 'true' : 'false'}</p>
 | 
			
		||||
                </>
 | 
			
		||||
              )}
 | 
			
		||||
            </div>
 | 
			
		||||
          </>
 | 
			
		||||
        )}
 | 
			
		||||
      </main>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user