A Simple Login System using Ethereum

///A Simple Login System using Ethereum

A Simple Login System using Ethereum

[vc_row][vc_column][vc_column_text]

 

A Simple Login System using Ethereum

In Ethereum, the addresses are (by definition) systems to prove ownership. The rightful owner of the address is who can perform operations with this address. So, this is the consequence of the underlying public-key infrastructure that is used to verify transactions. For example, we can create a login system based on Ethereum addresses.

In a login system, it is always created a unique identity that can be managed by whoever can pass a method to prove that the same entity that created the account in the first place is the same entity doing operations now. Actually, most systems have a username and a password. So, anytime the system requires proof of its identity, then it can request the password for that username. But, in Ethereum we already have a system for proving identities, which are the public and private keys.

For example, a simple contract (which can be used by any user to validate his ownership of an address) would have the next logic:

First, a user accesses a website to login. Then, when the user is not logged in, then the website requests the user to enter his digital address.

Then, the backend for the website receives the address for the user and creates a “challenge string” (to verify his identity) and a JSON Web Token (JWT). Then, these are sent back to the user.

Then, the user sends the “challenge string” (used to verify his identity) to the “Login contract” and stores the JSON Web Token (JWT) for later use locally.

Then, the backend listens for login attempts using the “challenge string” (used to verify the user’s identity) at the Ethereum network. When an attempt with the “challenge string” for the right user is seen, then it can assume that the user has proven its identity. Furthermore, the only user that can send a message with a digital address is the holder of the private key, and the only user that knows the “challenge string” is the user that received the challenge through the login website.

Furthermore, the user gets notified or polls the website backend for confirmation of his or her successful login. Then, the user must use the JSON Web Token (JWT) issued in step 2 for accessing the website. Or, a new JSON Web Token (JWT) can be issued after a successful login.

The Ethereum smart contract to validate his ownership of an address is the next one:

/***********************************************************************************/

pragma solidity ^0.4.2;

contract Login {

event LoginAttempt(address sender, string challenge);

function login(string challenge) {

LoginAttempt(msg.sender, challenge);

}

}

/***********************************************************************************/

In this contract Login, there is an event LoginAttempt, and a function called login that calls the LoginAttempt event.

This login contract is extremely simple. Furthermore, events are special elements in Solidity (Ethereum programming language) that are mapped to a system in Ethereum that allows special data to be logged. Furthermore, events are for monitoring the evolution of the Ethereum blockchain. So, clients can take actions when events are created. In case a user attempts to log in, then an event created with the challenge is broadcast. So, the system must receive a call from the rightful owner of the digital address that was passed to the third party website. Using this logic, we can be sure the sender was the one who performed the call.

Additionally, the “challenge string” is also broadcast, which means that anyone watching the blockchain knows the “challenge”. But this can’t be used to impersonate a user. Actually, a user can only interact with the backend through the session JSON Web Token (JWT). So, an attacker must know the Ethereum address, the challenge and the JWT issued with the challenge in order to impersonate a user. Since JSON Web Tokens (JWT’s) are signed, an attacker cannot create a valid JSON Web Token (JWT) to impersonate a user (even if the attacker has access to the challenge).

This is an example of the backend code. First, you will see how to watch for Ethereum events:

/***********************************************************************************/

const LoginContract = require(‘./login_contract.js’);

const loginContract = LoginContract.at(process.env.LOGIN_CONTRACT_ADDRESS ||

‘0xf7b06365e9012592c8c136b71c7a2475c7a94d71’);

// LoginAttempt is the name of the event that signals logins in the

// Login contract. This is specified in the login.sol file.

const loginAttempt = loginContract.LoginAttempt();

const challenges = {};

const successfulLogins = {};

loginAttempt.watch((error, event) => {

if(error) {

console.log(error);

return;

}

console.log(event);

const sender = event.args.sender.toLowerCase();

// If the challenge sent through Ethereum matches the one we generated,

// mark the login attempt as valid, otherwise ignore it.

if(challenges[sender] === event.args.challenge) {

successfulLogins[sender] = true;

}

});

/***********************************************************************************/

So, the “login_contract.js” file contains what is needed to inter-operate with our contract.

/***********************************************************************************/

// web3 is an Ethereum client library

const Web3 = require(‘web3’);

const web3 = new Web3();

web3.setProvider(new web3.providers.HttpProvider(‘http://localhost:8545’));

// This file is generated by the Solidity compiler to easily interact with

// the contract using the web3 library.

const loginAbi = require(‘../solidity/build/contracts/Login.json’).abi;

const LoginContract = web3.eth.contract(loginAbi);

module.exports = LoginContract;

/***********************************************************************************/

Actually, Web3 is the official client library to interact with Ethereum nodes, which are what actually connects to the rest of the Ethereum network. So, it performs “blockchain mining” (which is the block (which is a group of transactions) generation), transaction operations (such as create and send) and block verification.

The “Login.json” file is generated by the Solidity-smart-contract compiler, which is part of the standard Ethereum development tools. Actually, the Solidity compiler takes Solidity source code and turns it into Ethereum Virtual Machine (EVM) bytecode. Furthermore, it is uploaded to the Ethereum network an interface description file that can be used by Web3.

So, here are the HTTP endpoints:

/***********************************************************************************/

app.post(‘/login’, (req, res) => {

// All Ethereum addresses are 42 characters long

if(!req.body.address || req.body.address.length !== 42) {

res.sendStatus(400);

return;

}

req.body.address = req.body.address.toLowerCase();

const challenge = cuid();

challenges[req.body.address] = challenge;

const token = jwt.sign({

address: req.body.address,

access: ‘finishLogin’

}, secret);

res.json({

challenge: challenge,

jwt: token

});

});

app.post(‘/finishLogin’, validateJwt, (req, res) => {

if(!req.jwt || !req.jwt.address || req.jwt.access !== ‘finishLogin’) {

res.sendStatus(400);

return;

}

if(successfulLogins[req.jwt.address]) {

delete successfulLogins[req.jwt.address];

delete challenges[req.jwt.address];

const token = jwt.sign({

address: req.jwt.address,

access: ‘full’

}, secret);

res.json({

jwt: token,

address: req.jwt.address

});

} else {

// HTTP Accepted (not completed)

res.sendStatus(202);

}

});

app.post(‘/apiTest’, validateJwt, (req, res) => {

if(req.jwt.access !== ‘full’) {

res.sendStatus(401); //Unauthorized

return;

}

res.json({

message: ‘It works!’

});

});

/***********************************************************************************/

The “/login” endpoint receives a login request carrying a digital address for the user that wants to log in. So, the user must be the owner of such Ethereum address. It generates a JSON Web Token (JWT) and a challenge. Furthermore, the JSON Web Token (JWT) can only be used to access the /finishLogin endpoint.

First, the user must make a call to the login method of the login contract in order to prove his identity, and then the user can call the /finishLogin. So, the login method receives a single parameter, which is the challenge returned by the “/login” endpoint. So, the user must perform this call using the same account address that was passed to the “/login” endpoint. Then, the user can use any digital wallet (or Ethereum wallet) or client to do this.

Then, the user can use the /finishLogin endpoint to complete the login. So, the user must pass the JSON Web Token (JWT) returned by the “/login” endpoint to it. In case the login is successful, then a new JSON Web Token (JWT) with full access is returned. And, in the case the login is still pending, then an accepted HTTP status (202) is returned signalling proper verification of the login request is still pending. In the case the JSON Web Token (JWT) passed to “/finishLogin” is invalid, then an unauthorized HTTP status code is returned (401).

After the “/finishLogin” endpoint is called and the login process is completed, then the returned JSON Web Token (JWT) can be used to access other parts of the Application Programming Interface (API). In this case, the “/apiTest” endpoint is available. Then, it returns “It works” wrapped in a JSON object in case the user is logged-in.

Running the Example

Actually, building and deploying the example is not that simple. These are the steps to test our example:

1. GET AN ETHEREUM NODE CLIENT

You must have one Ethereum node client. Furthermore, the most popular is go-ethereum, which is a client written in Go.

Ethereum blockchain has different versions of the blockchain with different parameters. So, there are essentially two blockchains. The first blockchain is the main official blockchain. The second blockchain is the test blockchain.

The main blockchain never undoes (or delete) operations once they are confirmed. Since some operations require gas (which has a cost in Ether (cryptocurrency)), then the main blockchain is not ideal for testing your smart contracts. In the case of the test blockchain, this blockchain is much less strict about forks and changes. Furthermore, the test blockchain is also simpler to mine “Ether”(Ethereum’s cryptocurrency).

So, we could use the test blockchain in order to test our example. However, running a client node for any of the public networks is not simple because in order to be able to start doing transactions, the client must first verify all previous transactions in the blockchain. So, this means that bootstrapping a new client node takes quite a bit of time. But we can create a new, pristine private Ethereum blockchain to run our tests. In order to create this private Ethereum blockchain, you must run go-ethereum using the following command line:

/***********************************************************************************/

./geth –rpc –nat none –dev

/***********************************************************************************/

2. CREATE A NEW ETHEREUM ACCOUNT TO MINE SOME ETHER

The “geth” command can be used to interact with a running client. So, you must launch an interactive console connected to the running client:

/***********************************************************************************/

/geth attach ipc:/var/folders/ts/7xznj_p13xb7_5th3w6yjmjm0000gn/T/ethereum_dev_mode/geth.ipc

/***********************************************************************************/

The “IPC” file of this command can be found in the output from running the node in our first step. Look for the line that reads:

/***********************************************************************************/

IPC endpoint opened: /var/folders/ts/7xznj_p13xb7_5th3w6yjmjm0000gn/T/ethereum_dev_mode/geth.ipc

/***********************************************************************************/

Now in the “Geth” console type:

/***********************************************************************************/

personal.newAccount()

/***********************************************************************************/

Then, a prompt will appear requesting a passphrase, which will be used to perform any operations using this account. Furthermore, you must not leave the prompt empty, so you must choose a passphrase. Then, a new digital address will be returned by the function. In case you forget this address, you can list accounts by inspecting personal.listAccounts (which is a variable, and not a function).

Actually, the “geth” console is a JavaScript interpreter.

3. START MINING SOME ETHER

First, you must add some Ether (cryptocurrency) to our new account. The Ether (cryptocurrency) is required to perform operations in the blockchain. Ether (cryptocurrency) can be gathered in two ways: by receiving it from another account or by mining it. This is a private network for testing our code, so we will need to mine it. Actually, the private network (for testing smart contracts) is configured to be able to mine Ether (cryptocurrency) easily. So, you must use the next code to do it:

/***********************************************************************************/

miner.setEtherbase(personal.listAccounts[0]) // Hit ENTER

miner.start() // Hit ENTER

/***********************************************************************************/

You must wait seconds or minutes to have some Ether in your account:

/***********************************************************************************/

eth.getBalance(personal.listAccounts[0]) // Hit ENTER

/***********************************************************************************/

4. COMPILE AND DEPLOY OUR LOGIN CONTRACT

In order to simplify the process of compiling and deploying contracts, you will use truffle, which is a development framework for Ethereum for simplifying many common tasks. You can install truffle using the next command:

/***********************************************************************************/

npm install -g truffle

/***********************************************************************************/

First, you need to “unlock” the account in the Ethereum node client. Actually, unlocking is the process of decrypting the private-key and holding it in memory using the passphrase used to create it. This unlocking process allows any client libraries (like Truffle) connecting to the node to make operations on behalf of the unlocked account. Then, you must go to the “geth” console and use the next command:

/***********************************************************************************/

personal.unlockAccount(personal.listAccounts[0]) // Hit ENTER

/***********************************************************************************/

Now you can switch to the solidity directory where is our sample application. Then, you must edit the truffle.js file and set your newly created address as the from key. Then you must run the next command:

/***********************************************************************************/

truffle migrate

/***********************************************************************************/

The migrate command compiles and deploys the smart contracts to the Ethereum network on behalf of the account set in truffle.js. So, you will get the digital address of the newly deployed contract. You should save this digital address.

5. INSTALL AN ETHEREUM WALLET (DIGITAL WALLET)

Ethereum wallets are convenient interfaces for users to interact with the Ethereum network. You can use it to send and receive Ether (cryptocurrency), deploying smart contracts or making calls to them are all operations usually supported by wallets. Actually, Mist is the official Ethereum wallet. You should download it and install it.

Then, you need to tell Mist to connect to our private network rather than the public main or test networks. So, you must run Mist from the command line like so:

/***********************************************************************************/

./Ethereum\ Wallet –rpc /var/folders/ts/7xznj_p13xb7_5th3w6yjmjm0000gn/T/ethereum_dev_mode/geth.ipc

/***********************************************************************************/

So, the IPC file is the same file used by the “geth” console and can be gathered from the “geth” output logs.

6. TELL THE ETHEREUM WALLET OF THE CONTRACT

Actually, there are many contracts in the Ethereum network. Furthermore, digital wallets need to know a contract’s address and interface before being able to interact with them. Then you must tell Mist about the Login contract. Then go to Contracts -> Watch Contract (which is at the top right).

Then you must complete the fields as follows:

/***********************************************************************************/

Name: Login

Contract Address:

JSON Interface: the abi from Login.json. For convenience it is pasted below. Copy and paste it in Mist.

/***********************************************************************************/

Then, you can use the next command:

/***********************************************************************************/

[ { “constant”: false, “inputs”: [ { “name”: “challenge”, “type”: “string” } ], “name”: “login”, “outputs”: [], “payable”: false, “type”: “function” }, { “anonymous”: false, “inputs”: [ { “indexed”: false, “name”: “sender”, “type”: “address” }, { “indexed”: false, “name”: “challenge”, “type”: “string” } ], “name”: “LoginAttempt”, “type”: “event” } ]

/***********************************************************************************/

So, you should try to test it and send some Ether (cryptocurrency) to the smart contract: (Contracts -> Login -> Transfer Ether & Tokens). Then, you should send 1 Ether (cryptocurrency) or any other amount less than your balance. Then, you will need to provide the passphrase for your account.

7. DEPLOY THE BACKEND

You should go to the backend folder and run:

/***********************************************************************************/

npm install

node app.js

/***********************************************************************************/

8. SERVE THE FRONTEND

You should go to the frontend folder and run the next commands:

/***********************************************************************************/

npm install -g static-serve

static-serve

/***********************************************************************************/

So, you may use any other simple static HTTP server such as Python’s SimpleHTTPServer. In case you do it, then you must make sure to serve the app in port 9080 due to CORS.

9. TEST EVERYTHING TOGETHER!

You should open your browser at http://localhost:9080. Then, you should attempt to login by putting your digital address in the input field. Then a “challenge string” will be generated. Then you should go to the Mist (Ethereum Wallet) and go to the Login contract. You should see “WRITE TO CONTRACT” at the right. Then, you should select the login function and paste the challenge into the text fill that appears there. Then you should click on Execute. Then, you must input your passphrase and send the transaction.

Then, you can switch back to the login page. Then, the login will be completed and a welcome message will appear.

In conclusion, this example shows how a typical Ethereum user can use his existing Ethereum account to log in to any third party website supporting Ethereum. Furthermore, it wasn’t used a central server. So, there is no central authority validating the user. Actually, it is the Ethereum network that does so.

Aside: Securing Applications with Auth0

In case you are building a B2C, B2B, or B2E tool. Auth0 can help you focus on the special features of your product. Actually, Auth0 can improve your product’s security with state-of-the-art features like passwordless, breached password surveillance, and multifactor authentication.

Conclusion

In conclusion, it was explained Ethereum blockchain, which is a decentralized, blockchain-based framework for developing applications. These applications run on each node. Actually, each state transition produced by them is validated and recorded by the blockchain. So, Ethereum blockchain is more than just cryptocurrency transactions or simple non-Turing complete contracts. So, the power of distributed apps is just beginning to be tapped.

[/vc_column_text][/vc_column][/vc_row]

By |2019-03-15T19:31:31+00:00January 5th, 2018|Categories: Blockchain blogs, Blog|Tags: , , |1 Comment

About the Author:

Comments are closed.

Social media & sharing icons powered by UltimatelySocial