[Ethereum] How to login with web3 without MetaMask

infurametamaskweb3js

Is it possible to sign a user in web3 without MetaMask? I am trying to execute a smart contract I created and I'm using Infura to connect to the Kovan test network, but web3.eth.accounts[0] is undefined. How can I sign a user in without having to use MetaMask? Is this even possible? If not, how should I approach this problem? Please and thank you!

Best Answer

What you should do in this case is use the web3-provider-engine. An example code snippet functioning with a custom private key and Infura API URL (Or even TestRPC) would be the following:

//Provider Engine sub-modules

const ProviderEngine = require('web3-provider-engine')
const CacheSubprovider = require('web3-provider-engine/subproviders/cache.js')
const FixtureSubprovider = require('web3-provider-engine/subproviders/fixture.js')
const FilterSubprovider = require('web3-provider-engine/subproviders/filters.js')
const VmSubprovider = require('web3-provider-engine/subproviders/vm.js')
const NonceSubprovider = require('web3-provider-engine/subproviders/nonce-tracker.js')
const RpcSubprovider = require('web3-provider-engine/subproviders/rpc.js')

//EthereumJS Wallet Sub-Provider

const WalletSubprovider = require('ethereumjs-wallet/provider-engine')
const walletFactory = require('ethereumjs-wallet')

//Web3 Module

const Web3 = require('web3')

//Wallet Initialization

var privateKey = "3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266"
var privateKeyBuffer = new Buffer(privateKey, "hex")
var myWallet = walletFactory.fromPrivateKey(privateKeyBuffer)

//Engine initialization & sub-provider attachment

var engine = new ProviderEngine();

engine.addProvider(new FixtureSubprovider({
  web3_clientVersion: 'ProviderEngine/v0.0.0/javascript',
  net_listening: true,
  eth_hashrate: '0x00',
  eth_mining: false,
  eth_syncing: true,
}))

// cache layer
engine.addProvider(new CacheSubprovider())

// filters
engine.addProvider(new FilterSubprovider())

// pending nonce
engine.addProvider(new NonceSubprovider())

// vm
engine.addProvider(new VmSubprovider())

// Here the URL can be your localhost for TestRPC or the Infura URL
engine.addProvider(new RpcSubprovider({
  rpcUrl: 'https://mainnet.infura.io/YOUR_ACCESS_TOKEN',
}))

// Wallet Attachment
engine.addProvider(new WalletSubprovider(myWallet))

// network connectivity error
engine.on('error', function(err){
  // report connectivity errors
  console.error(err.stack)
})

// start polling for blocks
engine.start()

//Actual Initialization of the web3 module

var web3 = new Web3(engine)

You will be able to sign any transactions you want with your supplied private key by specifying your public key as the "from" value in the settings object of each perspective web3 function call.

EDIT: I personally despise the web3 library and as a result, I decided to revamp the snippet to use the ethers.js library which has a more human-readable API:

//Provider Engine sub-modules

const ethers = require('ethers');
const Wallet = ethers.Wallet;
const Contract = ethers.Contract;
const utils = ethers.utils;
const providers = ethers.providers; 

//Note the "0x" appended at the start
let privateKey = "0x3a1076bf45ab87712ad64ccb3b10217737f7faacbf2872e88fdd9a537d8fe266";

let network = "http://192.168.1.1:8545";

//let network = "kovan";
//let network = "ropsten";
//let network = "rinkeby";
//let network = "homestead";

//let infuraAPIKey = "9LPi9fDukz8phfLXdy5K";

let provider = new providersJsonRpcProvider(network, 'homestead');
//let provider = new providers.InfuraProvider(network, infuraAPIKey);

let serverWallet = new Wallet(privateKey, provider);

That's basically it. You can now send transactions with it or construct Contract objects to interact with contracts with it. Refer to the ethers.js documentation for more.

Related Topic