-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ERC-1654 Dapp-wallet authentication process with contract wallets support #1654
Comments
Thanks to @pazams for writing this up. We think that there are lots of good reasons to use smart contract wallets, even for individual users. Hopefully, lots of Dapps will make this simple change to make that use-case viable (as we will for CryptoKitties!). |
Thanks for putting this together! Quick questions:
|
@PhABC thanks for these questions!
Correct. For an authentication flow, we have to first recover the signer in any case since we want to first validate in case of an external wallet. If that doesn't match, we can check under assumption of a contract wallet, which then we can already use the recover result from previous step.
Yes, this proposal assumes keys are pre-registered. It be may done with https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#addkey for EIP-725 wallets, but it's also valid for the keys to be hardcoded - the implementation strategy is up to the wallet. As for support for multi-sig, that's an excellent point! @PhABC What are your thoughts? |
I think this is fine for some use cases, but it's a bit less general than 1271 since it prevents other types of signatures schemes than ECDSA.
That makes sense! Yes, I think a guideline for off-chain processes like the one you are proposing can be very useful. Would you mind commenting on #1271 with your thoughts? I would like to see it being finalized pretty soon as it's relatively simple, but not many people are participating in the discussion as of now. |
Hey, I just published an article on "automatic authentication signatures" I guess this could be part of a different EIP but thought worth mentioning here. |
@PhABC, done. @wighawag, you have some interesting points. Here you wrote: "Upon signing, the origin (could be the hash of the origin) is inserted as part of the message to be signed". I definitely see the value there. How will that work with a wallet like MetaMask? Since the interface of dapp-wallet communication in web wallets is javascript, how can such thing be enforced with today's tech? where's the best thread to continue this discussion? |
@pazams For discussion regarding such "origin based" signature scheme, I initially thought (and still think) it should be part of #712 but the consensus (at least for now) seems to be that a separate EIP would be a better option. I am planning to write such EIP but for now the best place of discussion might be the ethereum magicians forum where I posted the article link and a quick summary at https://ethereum-magicians.org/t/3-proposals-for-making-web3-a-better-experience/1586 The 3 proposals also include an encryption/decryption scheme which should allow a seamless syncing mechanism for dapps. Encryption/decryption is currently being implemented by Metamask (though I am not sure what their exact plan is in this regard) and some discussion happened over there : https://ethereum-magicians.org/t/the-ux-of-eip-1024-encrypt-decrypt/1243 As for the authentication signature (that do not require origin checks) I added a link and a quick summary to the ethereum magicians forum, see here : https://ethereum-magicians.org/t/automatic-authentication-signature/2429 |
I think this should be revisted for the new ERC725 v2, where the owner account at key I'll plan on updating the #725 issue soon. |
@frozeman thanks for pointing this out! Let's assume a dapp get's a 130 byte signature as result of sign-in with personal sign flow. That's twice as long from the expected signature (user is using a multi sig wallet). The be able to query 725 methods, it first needs to split the signature into 65 byte chunks, recover each of the public keys, and query each of them. That could work, however, with |
I can't find the EIP in the EIP folder ; https://github.com/ethereum/EIPs/tree/master/EIPS Any help? |
I don't understand why EIP1271 cant be used to achieve exactly the same as proposed here, but 1654 seems limited to the signature format of bytes32. As a DApp developer, why should I use 1654 instead of 1271? |
@PhABC , that's because the PR has been stuck since June with no reviewers follow up 😞
@3esmit , see #1271 (comment) for an explanation. |
@pazams Any special reason for not using the latest spec of 1271? The comment you linked suggests it as an arbitrary decision. I hope this standard becomes compatible with final 1271. |
I agree with the variation of ERC1271 as added here, and discussions in #1271 are ongoing to adopt the standard to the version with |
@frozeman |
@3esmit I still see a non-compatible version here https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md . |
Once we finalised we can make a new PR to the EIP doc |
@PhABC @frozeman @3esmit |
hey all, this might be relevant to check out: https://github.com/arcadeum/ethauth.js / https://github.com/arcadeum/go-ethauth -- it is an authorization scheme using eip712 which supports EOA's and contract wallets implemented in both Typescript and Go. The idea is a dapp makes an auth request of some claims (dapp name, expiry, origin domain), asks a wallet to sign the payload with eip712, and then encodes an ethauth-proof string. You can use the ethauth-proof directly even as an http handler/middleware, but since for contract wallets you need to call isValidSignature remotely, its not ideal to do the check per request. Instead you can think of it somewhat like OAuth, and use the ethauth claims proof and exchange it for a JWT token. |
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. |
eip:
title: Dapp-wallet authentication process with contract wallets support
author: Maor Zamski (@pazams)
discussions-to:
status: Draft
type: Meta
created: 2018-12-12
First draft
Simple Summary
An off-chain process for dapps to prove actionable control (informally, "ownership") over a public Ethereum address using
eth_sign
. Supports both external wallets and contract wallets.Definitions
contract wallet
A contract account deployed with the intent to be used as the ownership address for on-chain assets (including ether, ERC-20 tokens, and ERC-721 NFTs). It has the ability to transfer ether or dynamically execute actions on other contracts (acting as the owner of assets controlled by those contracts). Common examples of contract wallets aremultisig wallets
(such as the ones provided by Gnosis and Parity) andidentity contracts
, as defined in ERC-725.external wallet
An externally owned account, controlled by a private key. Currently, most on-chain assets are owned by such accounts. A common example for an external wallet are the wallets generated by MetaMask.actionable control
A public key is defined to have actionable control over an address if either:ACTION
as defined in EIP-725.Abstract
The authentication process starts with the dapp client component requesting a message signature from the wallet.
The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has actionable control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets and EIP-725 contract wallets. For this process to be compatible with any other contract wallet, it requires the wallet to implement a small subset of EIP-725.
Motivation
Dapps frequently offer a customised off-chain user experience in addition to their smart-contract interface. For example, a dapp may provide a push notification feature to their users, allowing them to stay notified about successful state changes associated with their public addresses. For these type of features, a dapp needs a way to authenticate that a user has actionable control over the public address associated with their account.
A common practice dapps use in an authentication process is to only check if a recovered public key matches the requested authentication address. For contract wallets, this check is broken, as there is no corresponding private key to which to generate a signed message, and hence why some dapps are inaccessible for contract wallet users. It is therefore argued that a broader approach is needed.
Specification
Dapp
On the dapp side, the dapp-wallet authentication process MUST follow these steps:
eth_sign
.eth_accounts
.0xdc3d2a7b
or just thekeyHasPurpose
method as a subset of it using the EIP-165 interfaceID0xd202158d
.A challenge message SHOULD contain a random component. This will reduce the risk of replay attacks.
A challenge message SHOULD be generated by the dapp backend AND not get sent back as input from the dapp client, but be persisted in the backend for at least the entirety of the authentication process. This will remove the risk of accepting forged challenges.
The following algorithm MAY be used by dapp backend when authenticating users with personal signed messages:
Wallet
External wallet
Any software agents managing external wallets are not required to make any changes to continue to work with this process.
Contract wallet
When passed the ACTION
purpose
parameter of2
, the method MUST returntrue
if a key is present AND it can perform actions in wallet's name (signing, logins, transactions, etc.)When passed the ACTION
purpose
parameter of2
, the method MUST returnfalse
if a key is not present OR it cannot perform actions in wallet's name (signing, logins, transactions, etc.)It MUST return
true
if passed aninterfaceID
of0xd202158d
OR0xdc3d2a7b
. The former value represents a minimal subset of EIP-725 with just thekeyHasPurpose
method, while the later represents the full EIP-725 interface.Rationale
There has been a great body of work in standardizing contracts wallets, namely #725. However, for the current process of dapp-wallet authentication, interfaces for claims and key management are not required. Instead, a single contract method and a modification for the current process suffices. The small surface area of this proposal should allow it to be easily compatible across different types of contract wallets.
Backwards Compatibility
Implementation
Packages implementing the purposed algorithm:
Simple Summary
An off-chain process for dapps to assert whether an entity has authorized control (informally, "ownership") over a public Ethereum address using
eth_sign
. Supports both external wallets and contract wallets.Definitions
contract wallet
A contract account deployed with the intent to be used as the ownership address for on-chain assets (including ether, ERC-20 tokens, and ERC-721 NFTs). It has the ability to transfer ether or dynamically execute actions on other contracts (acting as the owner of assets controlled by those contracts). Common examples of contract wallets aremultisig wallets
(such as the ones provided by Gnosis and Parity) andidentity contracts
, as defined in ERC-725.external wallet
An externally owned account, controlled by a private key. Currently, most on-chain assets are owned by such accounts. A common example for an external wallet are the wallets generated by MetaMask.authorized signer
An entity is considered to have authorized control over a wallet if either:0x1626ba7e
to theIsValidSignature
contract call.Abstract
The authentication process starts with the dapp client component requesting a message signature from the wallet.
The client then proceeds to send the result to the dapp backend component along with the requested address to be used for authentication. The dapp backend recovers a public key from the signature, and checks if it has authorized control over the requested address. This check is done under consideration that the address may represent either an external wallet or a contract wallet. This process works with external wallets and contract wallets that support EIP-1271 with
0x1626ba7e
as a magic return value.Motivation
Dapps frequently offer a customised off-chain user experience in addition to their smart-contract interface. For example, a dapp may provide a push notification feature to their users, allowing them to stay notified about successful state changes associated with their public addresses. For these type of features, a dapp needs a way to assert that a user has authorized control over the public address associated with their account.
A common practice dapps use in an authentication process is to only check if a recovered public key matches the requested authentication address. For contract wallets, this check is broken, as there is no corresponding private key to which to generate a signed message, and hence why some dapps are inaccessible for contract wallet users. It is therefore argued that a more broader approach is needed.
Specification
Dapp
On the dapp side, the dapp-wallet authentication process MUST follow these steps:
eth_sign
.eth_accounts
.IsValidSignature
and expect the value0x1626ba7e
to determine whether the entity who signed the challenge has authorized control over the wallet.A challenge message SHOULD contain a random component. This will reduce the risk of replay attacks.
A challenge message SHOULD be generated by the dapp backend AND not get sent back as input from the dapp client, but be persisted in the backend for at least the entirety of the authentication process. This will remove the risk of accepting forged challenges.
The following algorithm MAY be used by dapp backend for authenticating users with personal signed messages:
Wallet
External wallet
Any software agents managing external wallets are not required to make any changes to continue to work with this process.
Contract wallet
Contract
The contract MUST implement the isValidSignature method as suggested by EIP-1271, yet in this variation:
Before recovering a public key, the
bytes32 hash
parameter MUST get hashed again with EIP-191, with 0 for "version" and the wallet address for "version specific data".The
bytes _signature
parameter MAY contain multiple concatenated signatures in case of a multi-sig wallet.The method MUST return
0x1626ba7e
if the public key (or keys) recovered from the signature (or signatures) are as expected according to the wallet's own key management logic. Otherwise the method MUST return0x00000000
.User agent
A user agent intended to work with the contract MUST generate signatures over a EIP-191 hash of a regular Keccak256 hash of the challenge message.
Rationale
EIP-1271 has done a great work with starting the discussion on a standard signature validation method for contracts. At the time of writing, it is still in draft, with several suggestions for the shape of the interface (e.g see here). This proposal takes one of the variations mentioned in the discussion, and builds on top of it a process for dapp-wallet authentication.
Backwards Compatibility
Implementation
Packages implementing the purposed algorithm:
Copyright
Copyright and related rights waived via CC0.
Thanks to @dete @Arachnid @chrisaxiom @igorbarbashin @turbolent @jordanschalm @hwrdtm for feedback and suggestions
The text was updated successfully, but these errors were encountered: