Skip to content
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

EIP-2255: Web3 Wallet Permissions #2255

Closed
Tracked by #5111
danfinlay opened this issue Aug 28, 2019 · 17 comments
Closed
Tracked by #5111

EIP-2255: Web3 Wallet Permissions #2255

danfinlay opened this issue Aug 28, 2019 · 17 comments
Labels

Comments

@danfinlay
Copy link
Contributor

danfinlay commented Aug 28, 2019

Opening an issue for discussing, for Web3 Wallet Permissions.

Discussion has started at ethereum magicians

Reposting the body here:


eip: TBD
title: Wallet Permissions System
author: Dan Finlay (@danfinlay), Erik Marks (@rekmarks)
discussions-to: https://ethereum-magicians.org/t/web3-login-permissions/3583
status: Work in progress (WIP)
type: Standard Track
category: Interface
created: 2019-08-22
requires: 1474

f7b2f29144e062e330125526167bc3fa359cd7aa_2_1380x474

Simple Summary

A proposed standard interface for restricting and permitting access to security-sensitive methods within a restricted web3 context like a website or "dapp".

Abstract

Web3 JavaScript wallet browsers may implement wallet_getPermissions and wallet_requestPermissions. This provides a standard interface for requesting permissions and checking a domain's current permissions status.

Motivation

Web3 Wallets are built around the responsibility of mediating the interactions between untrusted applications and a user's keys on their computer, getting appropriate consent from the user.

Today web3 browsers like MetaMask always prompt on a per-action basis. This provides security at the cost of substantial user friction. We believe that a single permissions request can achieve the same level of security with vastly improved UX.

The pattern of permissions requests is common around the web, from login with Facebook, Twitter, Github, and even Apple, making it a very familiar pattern.

facebook permissions

log in with apple

Many web3 applications today begin their sessions with a series of repetitive requests:

  • Reveal your wallet address to this site.
  • Switch to a preferred network.
  • Sign a cryptographic challenge.
  • Grant a token allowance to our contract.
  • Send a transaction to our contract.

Many of these (and possibly all), and many more (like decryption), could be generalized into a set of human-readable permissions prompts on the original sign-in screen, and additional permissions could be requested only as needed.

On the user's end, each of these permissions could be individually rejected (unchecked), or even attenuated, or adjusted to meet the user's terms (for example, a sign-in request could have a user-added expiration date, and a token allowance could be adjusted by the user when it is requested), making the web3 login a sort of user-revisable terms of use.

Specification

This proposal adds two new methods to a wallet's web3 provider API:

  • wallet_getPermissions
  • wallet_requestPermissions

The wallet_getPermissions method is used for getting an array of current permissions (empty by default), while the wallet_requestPermissions method is used for an application to request additional permissions.

These two methods are used to restrict a few hypothetical "restricted methods". The first such method we would suggest should be included as part of the standard is eth_accounts.

In this framework, the permission for a user to reveal their accounts would look like this:

const response = await provider.send({
  method: 'wallet_requestPermissions',
  params: [{
    'eth_accounts': {},
  }]
})

If this request was rejected, it would throw an error with a code value equal to 4001, per EIP 1193 errors, which the MetaMask team has canonized in a module eth-json-rpc-errors.

If the request is accepted by the user, then subsequent requests to eth_accounts will succeed, and return an accounts array as usual.

A call to wallet_getPermissions will then return a permissions schema object that describes the current permission.

const response = await provider.send({
  method: 'wallet_getPermissions'
})

Would return a value something like this:

[
  {
    invoker: 'ens://your-site.eth',
    parentCapability: 'eth_accounts',
    caveats: [
      {
        type: 'filterResponse',
        value: ["0x0c54fccd2e384b4bb6f2e405bf5cbc15a017aafb"]
      }
    ]
  }
]

Where invoker is a unique domain string used to identify the source of the current dapp. To start, this may include only https prefixes, but ens, swarm, ipfs, and others may all be valid sources in the future.

The term parentCapability comes from the ocap-ld spec, which these permissions objects are based on, and refers to the method that is being permitted.

The caveats array represents the specific restrictions applied to the permitted method.

You can see above how internally the user-selected account is transformed into a caveat, which is a restriction on the response values, in this case ensuring the page can only be notified of approved accounts. This also means this permissions system is forward-extensible to support logging into a page with multiple accounts.

Rationale

While the current model of getting user consent on a per-action basis has high security, there are huge usability gains to be had bo getting more general user consent which can cover broad categories of usage, which can be expressed in a more human-readable way. This pattern has a variety of benefits to offer different functions within a web3 wallet.

The eth_sendTransaction method itself could be a restricted method (requested by default with the provider.enable() method), and the user could at sign-in time decide whether they wanted to require confirmations, approve all transactions, or only approve transactions to a certain contract, or up to a certain token limit, for example. By restricting this method by default, wallets could prevent sites from spamming the user with popups.

If eth_call were a restricted method, then random websites would not be able to drain a user's subscription to a hosted provider, making it easier to protect services like Infura against DDoS attacks.

On-chain actions could be represented as a permission under this model, for example, the permission to send an allowance-setting transaction to a specific token address is virtually equialent to the approval of that transaction, except the site could choose to only invoke the transaction when it was needed. This could allow a standard interface for applications to request permissions which may require different actions depending on different types of accounts (hot wallets, hardware wallets, cold wallets, contract accounts).

The requestPermissions method could be expanded to include other options related to the requested permissions, for example, sites could request accounts with specific abilities. For example, a website like an exchange that requires signTypedData_v3 (which is not supported by some hardware wallets), might want to specify that requirement, maybe like this:

provider.send({
  method: 'requestPermissions',
  params: [
    {
      'eth_accounts': {
        requiredMethods: ['signTypedData_v3']
      }
    }
  ]
})

That type of API will also be up for discussion on The MetaMask repository.

This would allow the wallet to limit the user's options to valid ones, and allows dapps to ensure selected accounts are compatible with their service, while preserving the user's privacy regarding how they are storing their keys.

Implementation

We have a branch of MetaMask available now which adds these methods via an rpc-engine middleware called json-rpc-capabilities-middleware (or often RpcCap internally, for short).

The latest build of this branch of MetaMask can be downloaded from the draft pull request (look for the latest post by @MetaMaskBot). A guide to adding a custom build of MetaMask to Chrome can be found here.

This branch of MetaMask can be used with this sample site (source), which uses a couple sample permissions for demonstration purposes:

  • readYourProfile: We have bundled this build with an imaginary concept of a local "profile", a simple POJO. Eventually this could be extended to instead expose the user's 3box profile.
  • writeToYourProfile: This permission allows the requesting app to freely update/edit the user's profile.
  • sendEther: A permission allowing the sending of transactions.

sample dapp

It is notable that this branch is the first version of MetaMask that allows you to be connected to each site with a different account, which persists on that site, along with any other permissions granted to the site.

You can get more detailed API and type information on the RpcCap repository's readme.

New hypothetical and proposed permissions can be easily added to the restrictedMethods hash in the MetaMask permissions controller or proposed for discussion on the MetaMask/wallet-permissions-spec repository.

Copyright

Copyright and related rights waived via CC0.

@raymonddurk
Copy link

Thanks for tackling this! Are you thinking this should be approved every time you interact with the dapp? That is very pro user security and privacy but could lead to a poor UX. I am not sure how many dapps would require a persistent need to interact with your wallet but wouldn't want to say never.

@danfinlay
Copy link
Contributor Author

Are you thinking this should be approved every time you interact with the dapp?

No, I think this could take the place of the login prompt. It would be up to the wallet and user to choose and enforce a logout policy that made sense for that user’s security preference.

For example, an expiration timeout is a type of caveat we are sure to propose, because it can be so useful for security.

However, unlike traditional web 2.0, where the logout options and policy are provided by the grace of the site, web3 wallets can enforce the preferences of the user across any compatible site.

This could mean any site’s login prompt includes a list of permissions, and a “log me out after X inactivity” at the bottom.

@serapath
Copy link

serapath commented Sep 6, 2019

there is a broken link to https://w3c-ccg.github.io/ocap-ld/

@serapath
Copy link

serapath commented Sep 6, 2019

It would be cool if a dapp can request features which metamask does not support and then offer users alternative wallets or solutions for the kind of feature the user needs to be used in addition to metamask to solve the requirements of the dapp :-)

I responded in the above linked issues, because even though it's strongly related, it's more about "feature requests" than "permission requests".

Did you think of such a scenario?

@danfinlay
Copy link
Contributor Author

there is a broken link to https://w3c-ccg.github.io/ocap-ld/

They apparently just recently renamed it to zcap-ld, thanks for the catch!

It would be cool if a dapp can request features which metamask does not support and then offer users alternative wallets or solutions for the kind of feature the user needs to be used in addition to metamask to solve the requirements of the dapp :-)

I think it makes sense that different wallets would support different methods/permissions, and so maybe we can add to this spec to define an error of "method not supported by wallet", which a dapp developer could use to trigger an alternative-wallet suggestion flow. We probably just need to standardize an error code for that and we could add it. Could submit the error code as a PR here:
https://github.com/MetaMask/eth-json-rpc-errors

@danfinlay
Copy link
Contributor Author

I've opened a PR for this proposal: #2302

@danfinlay danfinlay changed the title EIP-xxx: Web3 Wallet Permissions EIP-2255: Web3 Wallet Permissions Oct 1, 2019
@hiddentao
Copy link

hiddentao commented Nov 3, 2019

the user could at sign-in time decide whether they wanted to require confirmations, approve all transactions

A note that if connecting via a hardware wallet then the dapp-facing "wallet" needs to be smart enough to not display this option (i.e. auto-approve tx) in the first place otherwise the user may get confused later on.

Also, an admin UI of sorts through which users can administer permissions previously set for Dapps is crucial.

@danfinlay
Copy link
Contributor Author

A note that if connecting via a hardware wallet then the dapp-facing "wallet" needs to be smart enough to not display this option (i.e. auto-approve tx) in the first place otherwise the user may get confused later on.

This is true. We may completely avoid auto-signing permissions and instead prefer delegated keys, which have intrinsic signing power.

Also, an admin UI of sorts through which users can administer permissions previously set for Dapps is crucial.

Agreed, and at MetaMask we are implementing exactly this. It will allow redaction and attenuation of active permissions.

@MicahZoltu
Copy link
Contributor

In the specification section it reads (emphasis mine):

The wallet_getPermissions method is used for getting an array of current permissions (empty by default), while the wallet_requestPermissions method is used for an application to request additional permissions.

I recommend removing the empty by default wording as the default permission set is something that should be up to the tool to decide on. Some users may want to give away some "public" account by default to all websites and for them the initial set of wallet_getPermissions for a given dapp would include eth_accounts.

@MicahZoltu
Copy link
Contributor

Would every method have a permission associated with it, or only certain ones? If only certain ones, how does one get a list of the methods from the provider that are gated by this system?

I don't see caveats specified anywhere in here, without standardization they are going to be nearly useless to dapps since we will not be able to write logic that switches on them. Also, it is unclear to me why dapps need to know the limits that the user may or may not have put on the system? Why does the dapp need to know that the accounts it is seeing are filtered down to a subset? That feels like an information leakage.

@om26er
Copy link

om26er commented Jul 26, 2020

I am trying to use Wallet Permissions to get permission from the user to "sign" any EIP712 data, that seems not to be possible. Or am I expecting EIP2255 wrongly for my use case ?

@om26er
Copy link

om26er commented Jul 27, 2020

What I am looking for is for my website to be able to get "permissions" from the user only once to be able to sign EIP712 transaction on its behalf. Is that possible with current implementation of things ?

@A13k2
Copy link

A13k2 commented Nov 17, 2021

any updates on this?
this issue is already older than 2 years (1000 years in crypto time)

@danfinlay
Copy link
Contributor Author

Hi there, checking in here, sorry for the infrequency.

Would every method have a permission associated with it, or only certain ones? If only certain ones, how does one get a list of the methods from the provider that are gated by this system?

Restricted methods would be up to the wallet/provider.

I am trying to use Wallet Permissions to get permission from the user to "sign" any EIP712 data, that seems not to be possible. Or am I expecting EIP2255 wrongly for my use case ?

Yes these are not a way to get an EIP-712 signature from the user. At some later point these permissions could be extended to include a signature in the proof field of the returned data.

any updates on this?

I guess we should open the PR for this interface. This interface is easy to add to any RPC-API provider using rpc-cap, which has been in production at MetaMask for >2 years now.

@danfinlay
Copy link
Contributor Author

Oh, this was merged, it's just been in a "draft" state:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2255.md

@github-actions
Copy link

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.

@MicahZoltu
Copy link
Contributor

Closing this for housekeeping purposes. Feel free to continue using this issue for discussion about EIP-2255.

Note: If 2255 is pulled out of stagnant, the discussions-to link should be moved to a thread on Ethereum Magicians.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants