Skip to content

An web3 app using Vue.js and Node.js to authenticate Ethereum user and verify NFT ownership.

Notifications You must be signed in to change notification settings

yxuco/vue-nft-delivery

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NFT Token Ownership Verification with Vue.js and Node.js

This project uses an NFT usecase to illustrate how to implement a Web3 application from scratch.

We choose to use the Express Node.js application framework to implement the backend API service, and Vue.js JavaScript framework to implement the web user interface.

The application can verify that a crypto wallet owner really owns a specified NFT token. In the application's web UI, a user can enter an NFT contract address and a token ID to be verified. The UI will send a message signing request to the user's wallet plugin (assuming that user is logged in to a MetaMask Chrome plugin), and prompt the user to sign a message containing the NFT contract address and token ID. After the user signs the message by using the private key in the wallet, the signature will be sent to a backend API service for verification. The API service will extract the signer's public address from the signature, and query the blockchain to retrieve the owner of the specified NFT token, and then return both the verified signer's address and the token owner's address. If these 2 addresses match, it proves that wallet owner must be the current owner of the specified NFT token.

Prerequisite

Install Node.js

I use zsh on a Mac, and installed Node.js by using nvm i.e.,

touch ~/.zshrc
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install node

Verify that Node.js and npm are installed correctly, i.e.,

nvm -v
npm -v
node -v

Configuration

Install MetaMask plugin for Chrome from here, and then create an account if you do not already have a wallet.

Create an account at infura.io, and then create an Ethereum project. Copy the endpoint URL for the rinkeby test network, and use the URL in the API server configuration file, api/config.json.

Start the application as is

For development by default, this application will start a backend API server on port 3070, and a Vue web UI proxy on port 8082. You can start these processes in separate terminals as follows.

# start the Node.js API server on port 3070
cd api
npm install
npm run dev

# start the Vue.js UI proxy on port 8082
cd nft-app
npm install
npm run serve

View the web UI in a Chrome browser at http://localhost:8082/. Login to your wallet in MetaMask browser plugin. In the web UI, enter a Token ID of 1 through 4, and select an NFT contract, then click the Sign button to see the verification result, which should look like the following:

Verify Signature

Implement the API service from scratch

In an empty project folder, e.g., ~/jsprojects/vue-nft-delivery, create a JavaScript project from scratch, i.e,

mkdir api -P && cd api
npm init

Enter the following parameters when prompted by the command npm init:

package name: (api)
version: (1.0.0)
description: backend for nft-delivery
entry point: (index.js) server.js
test command: test
git repository: https://github.com/johndoe/vue-nft-delivery
keywords: nft
author: John Doe
license: (ISC)

This will create a file package.json, which you can edit if you want to change any of the parameters.

We use the Express framework to implement backend service APIs. Besides, for convenience during the development, we use nodemon to restart the API server automatically whenever the code is updated. So, add these dependencies for runtime and dev-only.

npm install --save express
npm install --save-dev nodemon

The service APIs will use ethers.js to verify message signature, and use web3.js to connect to an Ethereum node and call smart contract methods. For development, we use webpack to build production bundle of the application scripts and assets. So add these dependencies as well.

npm install --save ethers web3
npm install --save-dev webpack webpack-cli

We are now ready to write the API code. All APIs are implemented in server.js. If you are not familiar with the express framework, you may find the references at the end of this doc helpful.

The server.js implements 2 APIs:

  • /api/contracts will return a list of pre-configured NFT contracts whose tokens can be verified by this application.
  • /api/verify will verify the user's signature of a NFT token ID, and retrieve the owner of a specified NFT token from an Ethereum node.

It also uses express.static to serve static web content in a /public folder, as well as the application bundle of the web UI in /nft-app, which we'll implement in the next section.

During the development, the API server will listen on an HTTP port, but for production build, we should change it to use HTTPS.

The configuration parameters are read from the file config.json, which includes

  • port is the API server's listen port.
  • infura is the URL of Ethereum node in infura. You can create a free account in infura, and then create a project, and copy the project's endpoint for the Ethereum network where your NFT is minted and/or traded.
  • contracts is a list of NFT contracts to be handled by this application. The sample entries list 2 NFT contracts that I created on the rinkeby test network. This list will be displayed as a selection list on the web UI that we'll implement in the next section. If you are interested in how to create such NFT contracts from scratch, refer to the Sample NFT project.

The API /api/verify uses the contract ABI of the standard ERC-721 specification to fetch the owner address of a specified token. Thus, we store a copy of the ABI definition in erc721.json.

Create webpack.config.js for production bundle. Note that we'll build the production bundle to a parent ../dist folder where we can add the web UI bundle later. We also added a rule to avoid the build error Can't resolve 'electron' for web3.js.

Edit the scripts in package.json for development and production. The production start script assumes that the application bundle is produced in the parent ../dist folder.

Start the API server using command npm run dev, which uses nodemon to watch files, and so the API server will automatically restart whenever the code is updated.

Verify the API server by sending a request from another terminal: curl http://localhost:3070/api/contracts.

Build the production bundle using command npm run build. Start the production server using command npm run start.

Implement the Vue web UI from scratch

In the project folder, e.g., ~/jsprojects/vue-nft-delivery, create a Vue.js project named nft-app:

# install Vue CLI globally if it is not done already
npm install -g @vue/cli

# create new project
vue create nft-app

We use the Bootstrap Vue 3 framework to build responsive web UI. It uses BootstrapVue web components as described here, and Bootstrap CSS classes as described here.

The web UI uses ethers.js to sign messages, and uses axios to call backend APIs over HTTP/HTTPS. So add these dependencies:

cd nft-app

# dependencies for message signature and verification
npm install --save axios ethers

# dependencies for UI components and css classes
npm install --save bootstrap bootstrap-vue-3

We are now ready to write code for the web UI. If you are not familiar with the vue.js or bootstrap-vue framework, you may find the references at the end of this doc helpful.

Edit the scripts in package.json to make it serve on port 8082.

Edit the configuration file vue.config.js to specify the URL of the backend API server as specified in the previous section, i.e., http://localhost:3070. It also specifies the output folder for production bundle, which we'll build later in this section.

Edit the file main.js to register bootstrap-vue, so it will be available for all the application components.

The file SigService.js implements service functions for the UI to interact with MetaMask wallet for signature calculation, and to call backend service APIs.

The only Vue.js UI component for this application is implemented in SignMessage.vue. When the component is loaded, it calls the backend API /api/contracts and uses the returned result to initialize the NFT contract selection list. When the user clicks the Sign button, it send a request to MetaMask wallet where the user can sign a message by using the private key in the wallet. When the signature is updated, a watcher method will pick the updated signature and call the backend API /api/verify, and then display the verification result. When HTTPS transport is used by the backend API server, this approach could be a reliable mechanism for web3 user authentication. For even better security, however, we may add a step to request a random nounce from the backend server, and so the user will sign a dynamically generated random message, instead of a static NFT token ID.

Edit the root component App.vue to include the SignMessage as a child component under the root.

Note that the file .eslintrc.js contains an ESLint rule to disable the syntax check for multi-word-component-names, and so component names do not have to use multiple words. It is not necessary for this project because the only component of the project, SignMessage contains 2 words. However, if you add a component with a single-word name, e.g., Header, you will see a compilation error:

error  Component name "Header" should always be multi-word  vue/multi-word-component-names

The additional ESLint rule in .eslintrc.js would be necessary to override the default behavior.

Start the web UI proxy server by using the following command. It'll pick up code changes automatically, and thus you do not have to restart it during development.

cd nft-app
npm run serve

View the web UI in a Chrome browser at http://localhost:8082/, and start testing.

Build production bundle

For production, we can build the applicaton bundle to the same ../dist folder and so the same Node.js server will serve both the API service and the web UI, as well as other static content in a public folder. As described in the API service implementation server.js, the API server bundle will be output to the root of ../dist, and the web UI bundle will be output to the sub-folder ../dist/nft-app. The following scripts will perform the build tasks.

cd ../api
npm run build

cd ../nft-app
npm run build

Start the production application server using the following command.

cd ../dist
node serer.bundle.js

View the web UI in a Chrome browser at http://localhost:3070/. Login to your wallet in MetaMask browser plugin. In the web UI, enter a Token ID of 1 through 4, and select an NFT contract, then click the Sign button to see the verification result.

You can add any other static HTML pages, such as sample files under /public to the folder ../dist/public, and so they can be viewed at http://localhost:3070/public.

If you update the server port and/or other configuration parameters in config.json, you'll have to rebuild the production bundles, and then restart the Node.js server.

References

About

An web3 app using Vue.js and Node.js to authenticate Ethereum user and verify NFT ownership.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published