owned this note
owned this note
Published
Linked with GitHub
---
title: Add a Google Account as Safe Recovery Method using Lit
description: Learn how to offer a recovery option for your users using Lit and AbstractinKit
image: /img/posters/abstractionkit-meta.png
keywords: [mpc,hosted-wallets,social-login, passkeys, biometrics]
---
# Add a Google Account as Safe Recovery Method using Lit (Guide 1/2)
This is the first of the two guides on how to add a google account as a recovery method for a Safe. In the second guide, we show the steps to execute the recovery.
## What is Lit Protocol?
[Lit](https://litprotocol.com) is a decentralized network for signing and encryption. One of their usecases is to enable users to login using various authentication methods like Social Logins and Email OTP.
To leverage the full potential of Account Abstraction, you can combine Lit with AbstractionKit to enable email / social recovery experience, while using a Smart Account as the smart wallet to sponsor gas for users, batch transactions, and more.
### Relevant links
For additional information during this guide:
- [How on-chain guardian recovery works](https://docs.candide.dev/wallet/plugins/recovery-with-guardians/)
- [Guardian Recovery SDK Reference](https://docs.candide.dev/blog/making-accounts-recoverable/)
- [Simple Recovery example on GitHub](https://github.com/candidelabs/abstractionkit/tree/experimental/examples/SafeAccountExamples/SocialRecovery)
- [Lit Documentation Website](https://developer.litprotocol.com/)
## Installation
### Install required dependencies
```bash
npm i abstractionkit@0.1.12 && @lit-protocol/lit-auth-client
```
### Configure .env file
Configure the values you created from Lit dashboard in an .env file
```ts
// Lit
LIT_API_KEY=Request Relay Server API Key from Lit at https://forms.gle/RNZYtGYTY9BcD9MEA
// Candide
BUNDLER_URL="Visit https://docs.candide.dev/wallet/bundler/rpc-endpoints/"
PAYMASTER_URL="Request an API key from Candide on Discord"
// Owner Public/Private Keys
OWNER_PUBLIC_ADDRESS=
OWNER_PRIVATE_KEY=
// Network Info
VITE_CHAIN_ID=
JSON_RPC_NODE_PROVIDER="From Node provider"
```
## Setup Guardian
### Initialize the Lit client and provider
- Connect to the Lit Network using LitNodeClient.
- Set up the LitAuthClient for authentication.
- Initialize a GoogleProvider for Google sign-in.
```ts
import { LitNodeClient } from "@lit-protocol/lit-node-client";
import { LitAuthClient, GoogleProvider } from "@lit-protocol/lit-auth-client";
import { ProviderType } from "@lit-protocol/constants";
const initalizeClientsAndProvider = async () => {
const litNodeClient = new LitNodeClient({
litNetwork: "datil-dev",
debug: true,
});
await litNodeClient.connect();
const litAuthClient = new LitAuthClient({
litRelayConfig: {
relayApiKey: "Anything",
},
litNodeClient,
});
console.log("Connected to Lit Node and Lit Auth Clients ✔️");
const provider = litAuthClient.initProvider<GoogleProvider>(
ProviderType.Google,
{
//redirectUri: VITE_REDIRECT_URI,
}
);
return { litNodeClient, litAuthClient, provider };
};
```
### Authentication with Gmail
- Generate Authentication Method
- Check if the user is already authenticated. If not, redirect to Google sign-in
```ts
import { AuthMethod } from "@lit-protocol/types";
const generateAuthMethod = async () => {
const url = new URL(window.location.href);
if (!url.searchParams.get("provider")) {
console.log("Signing in with Google...");
provider.signIn((url) => {
window.location.href = url;
});
} else if (url.searchParams.get("provider") === "google") {
const authMethod = await provider.authenticate();
return authMethod;
}
};
const authMethod = await generateAuthMethod();
if (!authMethod) {
return;
}
```
### Mint PKP (Programmable Key Pair)
```ts
import { LitAuthClient } from "@lit-protocol/lit-auth-client";
const mintWithGoogle = async (authMethod) => {
const pkp = await litAuthClient.mintPKPWithAuthMethods([authMethod], {
addPkpEthAddressAsPermittedAddress: true
});
console.log("Fetched PKP", pkp);
return pkp;
};
const pkp = await mintWithGoogle(authMethod);
console.log("Minted PKP ✔️");
```
#### Setup the Email Guardian Signer
```ts
import { PKPEthersWallet } from "@lit-protocol/pkp-ethers";
import { LitAbility, LitPKPResource } from "@lit-protocol/auth-helpers";
import { AuthCallbackParams } from "@lit-protocol/types";
const authNeededCallback = async (params: AuthCallbackParams) => {
console.log(`auth needed callback params`, JSON.stringify(params, null, 2));
const response = await litNodeClient.signSessionKey({
statement: params.statement,
authMethods: [authMethod],
resourceAbilityRequests: [
{
resource: new LitPKPResource("*"),
ability: LitAbility.PKPSigning,
},
],
expiration: params.expiration,
resources: params.resources,
chainId: 1,
pkpPublicKey: pkp.pkpPublicKey,
});
console.log("AUTHSIG", response);
return response.authSig;
};
const guardianSigner = new PKPEthersWallet({
litNodeClient,
authContext: {
getSessionSigsProps: {
chain: "ethereum",
expiration: new Date(Date.now() + 60_000 * 60).toISOString(),
resourceAbilityRequests: [
{
resource: new LitPKPResource("*"),
ability: LitAbility.PKPSigning,
},
],
authNeededCallback: authNeededCallback,
},
},
pkpPubKey: pkp.pkpPublicKey,
rpc: "https://yellowstone-rpc.litprotocol.com",
});
console.log("Created PKPEthersWallet using the PKP ✔️");
```
## Add The Email Guardian to the Smart Account
### Initilize a Smart Account
```ts
import { SafeAccountV0_2_0 as SafeAccount } from "abstractionkit";
const smartAccount = SafeAccount.initializeNewAccount([ownerPublicAddress]);
console.log("Initialized Smart Account using ownerPublicAddress ✔️", smartAccount.accountAddress);
```
### Enable The Recovery Module and Add the Guardian
```ts
import { SocialRecoveryModule } from "abstractionkit";
const srm = new SocialRecoveryModule();
const enableModuleTx = srm.createEnableModuleMetaTransaction(
smartAccount.accountAddress
);
// Note that the Guardian added is also a Smart Account
const guardianOwnerAddress = await guardianSigner.getAddress();
const guardianSmartAccount = SafeAccount.initializeNewAccount([guardianOwnerAddress]);
const addGuardianTx = srm.createAddGuardianWithThresholdMetaTransaction(
smartAccount.accountAddress,
guardianSmartAccount.accountAddress,
1n
);
```
### Sign and submit the UserOperation
```ts
import { CandidePaymaster } from "abstractionkit";
let userOperation = await smartAccount.createUserOperation(
[enableModuleTx, addGuardianTx],
jsonRpcNodeProvider,
process.env.BUNDLER_URL
);
const paymasterUrl = process.env.PAYMASTER_URL;
const paymaster = new CandidePaymaster(paymasterUrl);
userOperation = await paymaster.createSponsorPaymasterUserOperation(
userOperation,
process.env.BUNDLER_URL
);
userOperation.signature = smartAccount.signUserOperation(
userOperation,
[process.env.OWNER_PRIVATE_KEY],
process.env.CHAIN_ID
);
const sendUserOperationResponse = await smartAccount.sendUserOperation(
userOperation,
process.env.BUNDLER_URL
);
console.log("User operation sent. Waiting to be included...");
const userOperationReceiptResult = await sendUserOperationResponse.included();
if (userOperationReceiptResult.success) {
console.log(
"Successful User operation. Transaction hash: " +
userOperationReceiptResult.receipt.transactionHash
);
const isGuardian = await srm.isGuardian(
jsonRpcNodeProvider,
smartAccount.accountAddress,
guardianSmartAccount.accountAddress
);
if (isGuardian) {
console.log("Guardian added confirmed ✔️. Guardian address: " +
guardianSmartAccount.accountAddress);
} else {
console.log("Adding guardian failed.");
}
} else {
console.log("User operation execution failed");
}
```
---
That's it! You've successfully added a Guardian capable of recovering an account with an Email using Lit. If you're interested in learning more about how the recovery process works, you can explore further details in the [full repository](#), the [generic guide for recovery](#), and the [SDK documentation](#). These resources provide in-depth explanations and examples to help you understand the underlying concepts and implementation.
---