Securing blockchain access in a web application
Shivkumar Iyer
Full-Stack Web Developer | 7+ Years of Expertise | React, Node.js, TypeScript, Java | Scalable & User-Centric Solutions | Agile & DevOps Specialist
This article is the beginning of a series of technical articles on combining a full-stack web application built using React and Node JS with smart contracts written in Solidity and maintained using Foundry.
One of the first objectives of this app is to build a user friendly UI to be able to create and manage shared wallets. These shared wallets are similar to joint accounts with a primary owner, optional admins and multiple users. Usually, it is the owner who will deposit ETH into the wallet so that the users can withdraw for their expenses. The owner can determine the maximum withdrawal limit that each user is allowed to withdraw, and can also optionally add admins who will approve of special requests above this limit.
The objective is to make this as simple and intuitive as transferring money through an online bank account. Except that the app is enabled with additional features such as notifications for requests, low funds and many others.
Since the main purpose of this app is to enable regular folks to create and manage wallets, and other regular folks to be able to access and use the funds in the wallets, the gateway has been chosen to be Metamask. With the Metamask plugin, any user can create or import a wallet, add multiple accounts, and use the funds in these accounts as required. Moreover, Metamask provides a fair bit of security in the form of generating a secret phrase and private keys for accounts, and maintaining them in the browser storage in an encrypted manner. Therefore, using Metamask as a gateway to access the blockchain features of the app makes the process secure and also easy to use for any user who has some exposure to using cryptocurrency through Metamask.
For this purpose, I use the web3 npm package with React to gain access to the Metamask account. However, this request occurs only after the user securely logs into the app.
Logging into the app, brings the user to the dashboard which offers a number of utilities such as creating, managing and accessing shared wallets, tokens, accounts etc. Upon arriving at this dashboard, a user is now prompted for the login to the Metamask plugin.
Once users log in and arrive at the dashboard, they can view data stored in the database. However, to make transactions on the blockchain, they would need their Metamask account to be unlocked.
Such a design provides the advantage that a user will be asked for Metamask credentials only after logging in and not immediately on accessing the website. This increases the trustworthiness of the app, as the user is only asked for Metamask credentials after entering a secure and private area of the app, and not in the public areas of the app. Furthermore, a user can choose not to provide credentials if not performing any blockchain transactions, but rather, merely browsing through data from the local database.
This has been done using Context in React. The dashboard is a root component that is accessible upon a secure login. The dashboard component in turn has a number of child components related to wallets, tokens, accounts etc. By wrapping the dashboard component in a context that provides the web3 instance to all child components, a user can make transactions in all the dashboard utilities after signing in to Metamask.
The Node JS backend does not store any API keys nor makes any web3 requests through any intermediary such as Infura or Alchemy. Using Forge, a base contract factory is deployed on the blockchain, and the address and the ABI are available in designated directories of the Foundry app. The deployment of the base contract is a one-time process, and therefore, care can be taken to ensure that this deployment is secure.
For the user, all access occurs through Metamask only, and there is no need to disclose either private keys or secret phrases.
Interested to know more? The project is completely open-source and here is the GitHub repository: