ERC 1115 : Decentralized user authentication standard
madhavanmalolan opened this issue ยท 15 comments
eip: <to be assigned>
title: DAuth - Decentralized authentication mechanism for DApps
author: madhavanmalolan
discussion-to: madhavanmalolan@gmail.com
status: Draft
type: Standards Track
category: ERC
created: 2018-05-23
Simple Summary
This is an authentication mechanism like "Login with Facebook" and "Sign in with Google" that is completely decentralized and helps DApps authenticate users.
Abstract
DAuth is a specification for an alternative to OAuth that allows DApps to accept user logins in a completely decentralized way - helping the DApp acertain the Ethereum address owned by the user. This login uses a familiar username-password pair that would allow logins to happen from any device or environment without the need for external libraries and extensions like Web3.
Motivation
Many DApps that perform some form of personalization need to identify the user. Consider, for example, the case of a popular DApp - CryptoKitties. CryptoKitties is a web based DApp and allows users to view, buy, sell and breed CryptoKitties. The only way to login into the application is using MetaMask which is a Web3 injector. It is not possible to view My kitties using a device that doesn't have MetaMask installed even if I do not intend to make any transactions.
DAuth will enable DApps to allow users to establish their identity by proving the ownership of their Ethereum address.
Design
We first describe the Authentication Game which takes place to authenticate a user.
0. Registration
A user registers by setting up a HTTP server (called the Dauth server). The user generates a password and a public-private key pair and stores the private key and the hash of the password on the server. Then, registers a username on the smart contract by providing the desired username, the public key and the address of the DAuth server.
All usernames on the contract are unique.
1. DApp Login
To login into a DApp, the user provides the following to the endpoint that performs the authentication on the DApp.
- Code : This is a random string that identifies the current authentication session. The authentication will go through only once for a given code.
- HashCode :
sha3(sha3(password), code)
- Username : The username that was registered and confirmed on the smart contract.
In order to verify this request, the DApp will fetch the public key and DAuth server address from the smart contract.
The DApp shall then generate a Secret string - which may be a random string. It will then pass the following parameters to the DAuth server's verification endpoint.
- Code : As provided by the user
- HashCode : As provided by the user
- Username : As provided by the user
- Cipher : The Secret string encrypted using the user's public key
2. DAuth server verification
The DAuth server on receiving the request from the DApp, fetches the hash of the password and the private key from its database corresponding to the username in the request.
It then validates if HashCode = sha3(hash of password, code)
If the HashCode is valid, and the code has not been used before, it tries to decrypt the Cipher using the private key and sends the decrypted value back to the DApp
3. Verification
The DApp may authenticate the user if the response from the DAuth server is the same as the Secret it used to generate the Cipher.
Specification
Smart Contract
set
function set(string username, string dauth_url, string public_key) public returns (bool)
event NewUser(address from, string username, bool success);
Must insert a mapping between the msg.sender
and the username, DAuth Server address, and public key.
Must emit NewUser(address, username, true)
if successfully created, NewUser(address, username, false)
if it fails.
getUsername
function getUsername(address user_address) public view returns (string)
Returns the username associated with a given address. Returns a blank string if no username exists for that address.
getAddress
function getAddress(string username) public view returns (address)
Returns the address associated with the username. Returns a blank string if the username is not registered.
getDauthUrl
function getDauthUrl(string username) public view returns (string)
Returns the DAuth Server address associated with the username. Returns a blank string if the username is not registered.
getDauthPublicKey
function getDauthPublicKey(string username) public view returns (string)
Returns the public key associated with the username. Returns a blank string if the username is not registered.
DAuth Server
The DAuth server must expose two endpoints
Verification Endpoint
This is the endpoint using a POST request to the DAuth Server address. This takes as parameters
{
username : string,
cipher : string,
code : string,
hashcode : string
}
If verification is successful, returns
200
{ data : <decrypted value> }
else,
403
{ data : <reason for failure> }
Login Page
This is a GET request to the DAuth Server address. This takes as query parameter the verifier url.
On the webpage it must accept the username and password, generate the code and hashcode and transmit the username, code and hashcode to the verifier (DApp).
DApp
The Dapp must provide an endpoint called the verifier URL that is a GET request that can be accessed from a web browser. This endpoint gets the following query parameters : code, hashcode, username. This endpoint may respond accordingly based on the success of the login.
Implementation
Smart Contract
The smart contract is hosted on the Rinkeby testnet - Link
DAuth Server
A user may run a self hosted DAuth Server by cloning this repository.
For the sake of simplicity and a demo, a DAuth Server has been setup at dauth.co on which users may choose to host their credentials if they are not able to host a server on their own.
Verifier
The DApps may use a the promise based nodejs implementation, which abstracts out all implementation details.
Source
All the code for the smart contract and the Dauth Server are opensourced at this repository.
Demo
A demo is available at dauth.co
More details
A white paper is made available that digs deeper into technical details : dauth.pdf
How is it different from OpenID? What is the point of the contract here?
Hmm, OpenID is a specification for decentralised auth, not some solution. No trust required. It was linked to the respective Foundation at later stages of the development to coordinate the effort.
Apart from that governance thing, how is it different and/or better?
The example of Cryptokitties requiring MetaMask only is incorrect. Any web3 provider works as Cryptokitties uses message signing to verify accounts. I don't see how this EIP is an improvement over message signing, something widely understood, requires no gas or execution cost, and already built-in to every client.
Apologies there, by referring to MetaMask, I meant it as an example of a web3 provider. Though signing with MetaMask is free of gas, there are the following issues.
-
users still need to install an extension to enable web3 on their traditional browser. Though it is easy to install, it is not necessarily available on all platforms. Consider the case of accessing the dapp from a mobile application for example using an embedded Web view. I do not agree with the argument t around it being built in on all clients.
-
Users lose portability. You cannot login into your Crypto Kitties account from your friends' device unless you type in the 12 word phrase and then need to remember to delete it.
-
Using MetaMask couples payment with identity. Consider scams (pointing out because I have come across one such), which ask you to make a small transaction to login. But the actual amount that shows up while paying is magnitudes higher - for someone not paying attention, it is easy to click submit. Dauth decouples payment from identity. The same way an SSN is different from a credit card number.
The way the EIP is an improvement is that it allows for a much simpler user experience without making assumptions like web3 being available on client side.
Does that answer your question?
@ukstv The difference from openID or any OAuth provider is that anybody can set up a server that authenticate only them if they want. That doesn't require any permission or certification as is the case with OpenID.
Functionally it is similar to OAuth and hence OpenID. The governance is the only improvement when compared to OAuth.
Other improvements are over existing authentication that exist as of today on top of Ethereum.
Since Dauth servers store the users' private keys in their databases, could they pass through the verification step and log in to dapps that those user's are using if they were malicious? Is there any way for end-users or others in the network to check if servers are acting right, and to penalize them for their behaviour?
@yuzushioh That is a very good question!
In the design i assumed the DAuth server to be acting on behalf of the user anyways. If one doesn't trust the servers out there, they should host one themselves.
Google can signin on your behalf on any website too, in a way.
This model focusses on giving an opportunity to the users to not trust a central authority and set up their own servers without compromising on the UX.
That said, I think this is a really good question - and I do not have an answer on the top of my mind, but will love to take this conversation forward.
In this sense users have to host their own server in order for them not to trust anything centralized.
the DAuth server to be acting on behalf of the user
It is true that this model gives an opportunity for users to handle their own actions by themselves, but I think it is far from possible for most of people to host their own servers. It may need more considerations about this.
I agree with @EvilJordan - I'm not following the benefit here.
Having users sign a message and decrypting serverside with something like eth-sig-util is an easy to use, gasless flow. I made a Javascript wrapper around doing just this:
https://www.npmjs.com/package/eth-auth
which exposes a single function, authenticate, letting a server pass in a userID (for their database), the claimed Ethereum address of the user, the encrypted signature & the plaintext message. The message could be an authentication token, a phrase or even a terms of service agreement.
I don't think this would be appropriate for a Smart Contract because users aren't going to "run their own server to prove their identity" this is not what a user wants to do.
You mention the users not having to "remember a 12 word phrase".. but that sounds much easier than 1) Setting up a Dauth server & 2) connecting to that server on a friend's computer to login to a Smart Contract app.
Smart Contract apps depend on servers hosting the web page. This isn't a bad thing. We are going to have "centralized" server hosting for a while because of how hosting economics work, at least until developers teach users how to save offline webpages for pure Ethereum applications. However, many applications depend on private data.
I don't see a clear benefit out of this new standard, perhaps I miss something? Here's my thoughts:
Given the hypothesis that:
- the user can set up a server
- the server is trusted and is on behalf of the user
Why won't the app just communicates with the server and authenticates the user, via a standardized interface?
The smart contract in this proposal stores:
- username
- user's public key
- server address
Why can't the user just remember the username and server address, and public key is stored unencrypted on the server. This way, the app can simply request the public key from the server.
Why using a username to retrieve public information (server address, public key) from Ethereum would be better than using a username to retrieve public information from a trusted server (set up by the user itself)?
I know an excellent authentication app (MFA) that leverages on blockchain and is completely decentralized:
https://www.hydrogenplatform.com/hydro-app,
Also for user Digital Identity Aggregator, check out EIP #1495.
Why not just use Self Sovereign Identity?
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.