4.8 KiB
WebAuthETH
Say it fast five times. It's fun
Elevator Pitch: Buy an NFT with your fingerprint on a stock Android phone on Chrome.
What: Enable Webauthn keys to control ETH SC wallets.
Why: 1) Browser blockchain UX is cumbersome to use 2) Extension installs are bad for product conversion rates 3) Mobile blockchain is impossible without a dapp browser
Philosophy: We don't care too much about gas right now, it should work on as many devices as possible, done and working is better than perfect
Requirments: (email only used for multi device login and recovery)
First Use Flow
User arrives at a Dapper auth enabled app called Foobar through a Webauthn enabled browser for the first time. User has not used this app or Dapper auth or the Foobar app before.
-
User loads application page
-
Script tag in page loads
dapper.jswhich exposes aweb3 -
Script injects a login overlay over the web page with a dapper auth iframe
-
User clicks Log In with Dapper button. Application calls
dapper.authenticate(appId)which returns aPromise -
This triggers an windowed iframe at location
https://auth.dapperauth.com/appId=XYZ -
dapper.jslooks inlocalStoragefordapper-auth-credential-id-XYZ- will not find this key since user is new and a credential for XYZ does not exist
- Will trigger start API lookup for a valid app credential for this user
-
dapper.jslooks inlocalStoragefordapper-auth-userfor the user's email id- If not found user will be prompted to enter an email ID
- Fetch
https://auth.dapperauth.com/credentials/appId=XYZ&user=email- Response will return null if no credentials are currently associated with this appId
- will trigger the wallet create flow
-
Dialog opens, presenting the user with the app's info and requested permissions
- User taps accept in the dialog
- If the user declines, throw
UserDeniedPermission
-
Call
navigator.credentials.createwith a preset create tx / challenge below. User will be prompted to create a new Webauthn credentiallet tx = 'CREATE' let challenge = kekkack(payload) let webAuthnResponse = await navigator.credentials.create({ payload, challenge, ...params }) let { pubKey, sig } = getPubKeySignature(webAuthnResponse)We use the returned
responseto set the compressed Ed25519pubKeyandsigwhich is a signature ofpubKeyover challenge. -
Trigger a recaptcha flow to get a
captchatoken from Google -
Establish Websocket to
https://auth.dapper.com/register?payload=2f3a42...Transmit this payload base64 encoded to establish connectionlet payload = { appId, pubKey, sig, tx, captcha } paylod = window.btoa(JSON.stringify(payload))- Server will recieve socket connection requests at `auth.dapper.com/register``. It parses the message frame as JSON and does the following:
- Ensure
tx === "CREATE". If failed, reject the connection - Ensure
ecrecoverEd25519(sig) === pubKeyIf failed, reject - Verify the captcha with the Google. If it failed, reject
- Accept the socket connection and kick off the wallet creation
- Instantiate wallet smart contract with constructor arguments
(pubKey, appId), which will allow the new contract wallet to be used withpubKeyfor contracts related toappId - Wait for this contract creation transaction to be mined and publish the newly deployed wallet address event on a queue with
id=$pubKey - Listen for this queue event from your socket event loop and once you recieve it, write the wallet address to the client socket and terminate the connection after recieving an ack
- Instantiate wallet smart contract with constructor arguments
- Ensure
- Server will recieve socket connection requests at `auth.dapper.com/register``. It parses the message frame as JSON and does the following:
-
Dapper auth
iframerecieves this wallet address, acks the message and returns it to parent frame and minimizes its frame frome view. -
dapper.jsin parent frame constructs a wrapped instance ofweb3with.accounts[0]set to the newly created wallet address. -
Resolve the
Promisefordapper.authenticate(appId)
Todo
Scaffold a new vm precompile function for ed25519- Decide on a public key compression.
- Create a failing test with output from a call to
navigator.credentials.createagainst ecrecover25519 - Write implementation for
ecrecoverEd25519contract - Write a simple docker file, run new geth image with kube on GCP with a new testnet with
id=1337 - Deploy a test contract for
ecrecoverEd25519 - Write a passing test in JS with
trufflewith provider connected to newgethtestnet - Implement
web3.jswrapper with pubkey gen, compression methods that connects to ourgeth - Scaffold web3 instance that uses smart contract wallet implementation
- Deploy test contract and write a passing JS test with
navigator.credentials.createagainst new smart contract