/solidity-google-auth

Solidity and oracle based non-custodial lockbox that allows users to deposit ETH that can only be accessed by a recipient's Google account.

Primary LanguageSolidity

SocialLock - Smart Contract based Google Authentication

SocialLock is a smart contract based, decentralized, non-custodial lockbox that allows users to deposit ETH that can only be accessed by a recipient's Google account.

It works by storing a keccak256 hash of the recipient's email address in the SocialLock.sol contract and holding a balance for it. The recipient can withdraw ETH from the lockbox by providing a valid Google JWT that contains the recipient email address. In other words, the only way to withdraw ETH from the lockbox is to provide a valid JWT (signed by Google), and thus to have access to the recipient's Google account.

Google rotates public keys every 48 hours which is why an oracle is needed to fetch the latest public keys. The JWKSOracle.sol uses Chainlink to fetch the latest public keys from Google and store them in the contract. SocialLock.sol uses JWKSOracle.sol to verify the JWT.

For more info, check out this medium article.

Demo

Live Demo

Getting Started

  1. Clone this repo
  2. npm i
  3. npx hardhat test

The tests are based on a hardcoded JWT. The values for aud, kid, and n (RSA Modulus) are calculated based on this hardcoded JWT. For a live implementation, use the Oracle implementation in JWKSOracle.sol.

Smart Contract Deployment

The smart contract deployment always follows the same pattern: Start with the JWKSOracle.sol, the one that will retrieve the RSA public keys from Google, and then deploy the SocialLock.sol contract. For the JWKSOracle.sol you have two options: Use the ChainLink oracle or hardcode the public keys. Google's latest keys can be found here: https://www.googleapis.com/oauth2/v3/certs

JWKS Deployment with oracle (ChainLink)

For the oracle to work you need to be on a network that supports ChainLink. Our testnet oracle is deployed on Sepolia.

  1. npx hardhat run scripts/deploy_JWKSOracle.ts --network <network> (make sure to update the LINK token address in the contract in case your network is not sepolia)
  2. npx hardhat verify --network <network> <contract_address> (verification is optional and only needed for easier interaction on Etherscan)
  3. Fund the JWKSOracle contract with LINK. Use https://faucets.chain.link/sepolia to get LINK.
  4. After funding the contract, call the requestJWKS() function. The easiest way to do this is via Etherscan. Each call to requestJWKS() will cost 0.15 LINK.
  5. The ChainLink Oracle will automatically call the fullfill() function for you.
  6. Continue with SocialLock deployment

JWKS Deployment without oracle (hardcoded keys)

  1. Start a local node npx hardhat node
  2. npx hardhat run scripts/deploy_jwks.ts --network <network>
  3. Continue with SocialLock deployment

SocialLock Deployment

You need your aud and jwks values before deploying the SocialLock contract.

  1. Deploy SocialLock using the hardhat task npx hardhat deploySocialLock --aud <your_aud> --jwks <jwks_contract_address> --network <network>
  2. Verify the contract on Etherscan (optional) npx hardhat verify --network <network> <contract_address> <your_aud> <jwks_contract_address>

Getting the Google aud value

Follow the official Google documentation to get your aud value.

  1. Go to https://console.cloud.google.com/apis/credentials
  2. Create a new project
  3. Create a new OAuth client ID
  4. Select Web application as the application type
  5. Enter http://localhost:5173/ (or whatever your local URL is) as the authorized redirect URI
  6. Click Create
  7. Copy the Client ID value
  8. It should look like this 1234567890-1234567890.apps.googleusercontent.com. This valued is referred to as clientID in the frontend, and it will be included as the aud value in your JWT.

Frontend Start

  1. cd frontend
  2. Rename .env.example to .env.local
  3. Copy/paste the SocialLock contract address into frontend/.env.local
  4. Copy/paste your Google clientID into frontend/.env.local
  5. npm i
  6. npm run dev

Testnet Contracts

Transaction Examples

Common Errors

  • "JWKS not found" -> make sure to call the requestJWKS() function on the JWKSOracle contract
  • "RSA signature invalid" -> make sure to use the correct aud value. The aud value is the clientID value from your Google OAuth client ID. It should look like this 1234567890-1234567890.apps.googleusercontent.com.
  • "Nonce does not match sender" -> The account that triggers the recovery is included in the JWT. Make sure to send the withdraw transaction from the same account that is included in the JWT.

Credits