Coder Social home page Coder Social logo

passkeys's Introduction

Passkeys Accounts

A collection of utilities to enable passkey accounts in viem & wagmi

Features

  • Create & Import EOA into a passkey wallet & use it to interact with directly with Ethereum
  • Bring your own passkey library, such as SimpleWebAuthn or React Native Passkeys
  • (Mostly) Unopinionated about how you store and handle the private key

... This is a work in progress so if you find any issues please let us know.

Installation

Install wagmi, viem & @forum/passkeys

pnpm install wagmi viem @forum/passkeys

Quick Start

This is one possible way to use this library to get started with largeBlob passkey accounts in wagmi.

It splits the setup process into three steps:

  1. First define a class to represent your site's passkey. This can wrap the navigator.credential api itself or some library like SimpleWebAuthn or react-native-passkeys.

    This should handle the calls to your server to verify that the calls are legit. See SimpleWebAuthn's server docs for an example of how to handle the verification.

    import { Passkey as AbstractPasskey } from '@forum/passkeys'
    
    export class Passkey extends AbstractPasskey {
    
        // - init your relaying party parameters 
        // ...
    
    	async create(options): Promise<RegistrationResponseJSON | null> {
    		const { challenge } = await getChallengeFromServer()
    
    		const passkeyResult = await await navigator.credential.create({ 
                ...options,
                challenge
            })
    
    		if (!passkeyResult) throw new Error('Failed to create passkey')
    
    		const verified = await getVerifiedPasskeyResult(passkeyResult)
    
    		if (!verified) throw new Error('Failed to verify challenge')
    
    		return passkeyResult
    	}
    
    	async get(options): Promise<AuthenticationResponseJSON | null> {
    		const { challenge } = await getChallengeFromServer()
    
    		const passkeyResult = await navigator.credential.get({
                ...options,
                rpId: hostname,
                challenge 
            })
    
            const verified = await getVerifiedPasskeyResult(passkeyResult)
    
    		if (!verified) throw new Error('Failed to verify challenge')
    
    		return passkeyResult
    	}
    }
  2. Define a custom hook to create the account

    import { useAccount, useConfig, useConnect, useDisconnect } from 'wagmi'
    import { generatePrivateKey, privateKeyToAddress } from 'viem/accounts'
    import { PasskeyConnector } from '@forum/passkeys'
    
    export const useCreateAccount() {
       const config = useConfig()
    
       const createAccount = async (
         username: string,
         privateKey = generatePrivateKey()
      ) => {
       		const passkey = new ForumPasskey()
       		const address = privateKeyToAddress(privateKey)
    
               // - generate the initial passkey for the new user & check that they are 
               // - using a device/browser that supports `largeBlob` webauthn extension
       		const credential = await passkey.create({
       			user: {
       				id: base64URLFromString(address),
       				name: username,
       				displayName: username,
       			},
       			extensions: { largeBlob: { support: 'required' } },
       		})
    
       		if (!credential?.clientExtensionResults?.largeBlob?.supported)
       			throw new Error('LargeBlob not supported')
    
               // - optional: if you have access to a secure store (e.g. keychain access)
               // - you can store the pk at this point
             	await storeInYourOwnSecureStoreForPrivateKeys({
                   credentialId: credential.id,
                   privateKey
               })
    
               // - init the viem passkey account
       		const largeBlobAccount = new LargeBlobPasskeyAccount({
       			passkey: new ForumPasskey(),
       			privateKey
       		})
    
               // - init the wagmi passkey connector
       		const connector = new PasskeyConnector({
       			account: largeBlobAccount.toAccount(),
       			config,
       		})
    
       		connect({ connector })
    
            // - you could choose to delay the following (storing the large blob)
            // - until the users first tx but for the example we do it here
          	const write = await passkey.get({
              	extensions: { largeBlob: { write: privateKey } },
              	allowCredentials: [{ type: 'public-key', id: credential.id }],
          	})
    
          	if(!write?.clientExtensionResults.largeBlob?.written)
                 throw new Error('failed to store large blob')
    
       		return credential
       	}
    
       	return { createAccount }
    }
  3. Integrate the hook into a normal wagmi connect flow

    import { useAccount, useConfig, useConnect, useDisconnect } from 'wagmi'
    import { generatePrivateKey, privateKeyToAddress } from 'viem/accounts'
    import { PasskeyConnector } from '@forum/passkeys'
    import { useCreateAccount } from './use-create-account.ts'
    
    function Profile() {
    	const { address } = useAccount()
    	const { connect } = useConnect()
    	const { disconnect } = useDisconnect()
     const { createAccount } = useCreateAccount()
    
    	if (address) {
    		return (
            	<div>
        			Connected to { address }
                	<button onClick={ () => disconnect() }> Disconnect < /button>
        		< /div>
            )
    y    }
    	return <button onClick={ () => createAccount('username') }> Connect Wallet < /button>
    }

passkeys's People

Contributors

peterferguson avatar

Stargazers

Kevin Bluer avatar Jack Clancy avatar 0xhaz avatar Daniil Popenko avatar DK avatar w3tester avatar Big Boss avatar  avatar John Johnson avatar  avatar  avatar Ryan Sproule avatar  avatar qdqd avatar sudo rm -rf --no-preserve-root / avatar Sock avatar Salief Lewis avatar Michael Demarais avatar  avatar

Watchers

Michael Demarais avatar  avatar

Forkers

lwandsyj

passkeys's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.