--- title: Ethereum Access Token description: A protocol for authorizing function calls from an off-chain service author: Chris Chung (@0xpApaSmURf), Raphael Roullet (@ra-phael) discussions-to: <URL> status: Draft type: Standards Track category: ERC created: 2023-05-08 requires: EIP-712 --- <!-- READ EIP-1 (https://eips.ethereum.org/EIPS/eip-1) BEFORE USING THIS TEMPLATE! This is the suggested template for new EIPs. After you have filled in the requisite fields, please delete these comments. Note that an EIP number will be assigned by an editor. When opening a pull request to submit your EIP, please use an abbreviated title in the filename, `eip-draft_title_abbrev.md`. The title should be 44 characters or less. It should not repeat the EIP number in title, irrespective of the category. TODO: Remove this comment before submitting --> ## Abstract <!-- The Abstract is a multi-sentence (short paragraph) technical summary. This should be a very terse and human-readable version of the specification section. Someone should be able to read only the abstract to get the gist of what this specification does. TODO: Remove this comment before submitting --> An Ethereum Access Token (EAT) is an [EIP-712](./eip-712.md) conformant, signed message, used by off-chain services to grant Ethereum accounts access to specific on-chain resources. EATs share similarities with JWTs; both are used for short-lived authorizations. However Ethereum Access Tokens are specifically designed to be verified on-chain and tailored to authorize smart contract function calls. ## Motivation <!-- This section is optional. The motivation section should include a description of any nontrivial problems the EIP solves. It should not describe how the EIP solves those problems, unless it is not immediately obvious. It should not describe why the EIP should be made into a standard, unless it is not immediately obvious. With a few exceptions, external links are not allowed. If you feel that a particular resource would demonstrate a compelling case for your EIP, then save it as a printer-friendly PDF, put it in the assets folder, and link to that copy. TODO: Remove this comment before submitting --> While other proposals tackle authentication ([EIP-4361](https://eips.ethereum.org/EIPS/eip-4361)) or authorization in a more narrow way ([EIP-2612](https://eips.ethereum.org/EIPS/eip-2612)), this specification allows developers to add a layer of access control to any function they create with minimal changes. It is best suited for use cases where end users should only be able to access specific on-chain resources themselves directly, by way of sending a transaction, provided they have been granted authorization by an off-chain service first. Examples of such scenarios include an off-chain verifier assessing eligibility requirements (e.g by verifying verifiable credentials) to mint a token or to interact with a smart contract that requires a certain compliance status. Therefore, this proposal enables off-chain systems to authenticate the controller of an Ethereum account in any way they want, before granting an authorization bound to said account. This specification is intended to improve interoperability in the Ethereum ecosystem, by providing a consistent machine-readable message format to achieve improved user experiences. EATs fill a void where access control requirements differ from current standard access control mechanisms (role-based access modifiers or checking that an address owns an NFT): - Desired acccess is short-lived - Criteria needs to be flexible/dynamic: updating the requirements for granting access doesn't require any update on chain - Soul-bound or other on-chain token semantics are not desired. Using any kind of "on-chain registry" to grant authorization places a burden on the owner of such registry to keep it up-to-date at all time, otherwise someone might be wrongly granted access. With EATs, on the contrary, users come to ask for an authorization which gives EAT issuers the opportunity to perform some checks and update their records before granting authorization. Additionally, relying purely on on-chain data comes with privacy concerns due to the public nature of most of current chains. When authorization needs to be granted based on sensitive or personally identifiable information, it is not recommended to store that information on-chain and perform a lookup. Ethereum Access Tokens provide an alternative which doesn't leak any PII on-chain. ## Specification <!-- The Specification section should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for any of the current Ethereum platforms (besu, erigon, ethereumjs, go-ethereum, nethermind, or others). It is recommended to follow RFC 2119 and RFC 8170. Do not remove the key word definitions if RFC 2119 and RFC 8170 are followed. TODO: Remove this comment before submitting --> The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### Overview An example flow integrated in a DeFi application is the following: 1. A user interacts with the DeFi's off-chain service, providing sufficient input for the off-chain service to ensure the user meets its criteria (for example, authenticates the user and/or make sure they possess valid credentials) 2. If authorization is granted, an EAT is issued to the user 3. The user then interacts with the gated smart contract function within the specified period of time passing the EAT as part of the transaction 4. The EAT is verified on-chain https://2466675578-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F17d4HfQK7hiYx9i4Vx7y%2Fuploads%2FmnSGej8Aae99phSkwu1y%2FScreenshot%202022-09-08%20at%2018.24.57.png?alt=media&token=0bf3a833-7f5a-4fd5-b29d-35ad4c4189ea An Ethereum Access Token MUST guarantee granular access control by binding it to specific parameters upon issuance. Then, on-chain EAT verification ensures that: - The function being called is the expected one - The function parameters are the expected ones - The function caller is the expected one - The function is being called in the authorized timeframe (i.e checking that the EAT is not expired) - The smart contract being called is the expected one - The authorization has been given by a valid issuer, i.e the EAT has been signed by one of the expected issuers ### Structure of an Ethereum Access Token An Ethereum Access Token is composed of a signature and expiry. ``` { uint8 v, bytes32 r, bytes32 s, uint256 expiry } ``` The signature is obtained using the typed structured data hashing and signing standard (EIP-712), signing over the following EAT payload: ``` struct AccessToken { uint256 expiry; FunctionCall functionCall; } struct FunctionCall { bytes4 functionSignature; address target; address caller; bytes parameters; } ``` - **expiry**: unix timestamp, expected to be before `block.timestamp` `FunctionCall` parameters correspond to the following: - **functionSignature**: identifier for the function being called, expected to match `msg.sig` - **target**: address of the target contract being called - **caller**: address of the current caller - expected to match `msg.sender` - **parameters**: `calldata` after stripping off the first parameters, namely `v`,`r`, `s` and `expiry` ### EAT Verification On chain, two contracts are necessary: an `AccessTokenConsumer` which is inherited by contracts needing to permission some of its functions and an `AccessTokenVerifier` which is responsible for verifying EATs. A modifier is added to functions that need to be permissioned with an EAT. Given a function such as: ``` function transfer(address recipient, uint256 amount) ``` Its permissioned version, protected via an EAT becomes: ``` function transfer( uint8 v, bytes32 r, bytes32 s, uint256 expiry, address recipient, uint256 amount ) requiresAuth(v, r, s, expiry) { ... } ``` The parameters `v`, `r`, `s`, `expiry`, which form an EAT, MUST be placed first, before any other parameters. The `requiresAuth` modifier is inherited from `AccessTokenConsumer` which verifies the Ethereum Access Token and consumes it: ``` modifier requiresAuth( uint8 v, bytes32 r, bytes32 s, uint256 expiry ) { // VF -> Verification Failure require(verify(v, r, s, expiry), "AccessToken: VF"); _consumeAccessToken(v, r, s, expiry); _; } ``` The `verify` function calls the `AccessTokenVerifier` registered upon construction to verify the EAT's integrity. Optionally, implementers can decide to make EATs non-replayable. This what `_consumeAccessToken(...)` does. It marks an EAT as consumed to prevent its re-use: ``` function _consumeAccessToken( uint8 v, bytes32 r, bytes32 s, uint256 expiry ) private { bytes32 accessTokenHash = keccak256(abi.encodePacked(v, r, s, expiry)); _accessTokenUsed[accessTokenHash] = true; } ``` ## Rationale <!-- The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other languages. The current placeholder is acceptable for a draft. TODO: Remove this comment before submitting --> - Single-use. The reference implementation guarantees non-replayability of EATs. But other implementations might favor a different approach. - Use of EIP-712. By conforming to EIP-712, EATs are interoperable with existing Ethereum infrastructure, and developers can use them to create access controls with minimal modifications to their existing code. It also ensures that EATs issued are bound to a specific chain. - Zero-knowledge proofs. Using ZKPs comes at a cost, including added complexity. EATs are not much more than signed messages which are simpler to reason around. While `ecrecover` is available in any Ethereum smart contract out of the box, ZKPs come in different flavors which hinders interoperability. ## Backwards Compatibility <!-- This section is optional. All EIPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The EIP must explain how the author proposes to deal with these incompatibilities. EIP submissions without a sufficient backwards compatibility treatise may be rejected outright. The current placeholder is acceptable for a draft. TODO: Remove this comment before submitting --> Any function can be gated with an EAT, apart from the special `receive` and `fallback` functions. ## Reference Implementation <!-- This section is optional. The Reference Implementation section should include a minimal implementation that assists in understanding or implementing this specification. It should not include project build files. The reference implementation is not a replacement for the Specification section, and the proposal should still be understandable without it. If the reference implementation is too large to reasonably be included inline, then consider adding it as one or more files in `../assets/eip-####/`. External links will not be allowed. TODO: Remove this comment before submitting --> TODO: add files as assets. AccessTokenVerifier + Consumer + Dummy Smart contract with a gated function + one JS file to show how to construct and sign an EAT. Mention that the reference implementation has been audited and used by Violet for Humanbound tokens. ## Security Considerations <!-- All EIPs must contain a section that discusses the security implications/considerations relevant to the proposed change. Include information that might be important for security discussions, surfaces risks and can be used throughout the life cycle of the proposal. For example, include security-relevant design decisions, concerns, important discussions, implementation-specific guidance and pitfalls, an outline of threats and risks and how they are being addressed. EIP submissions missing the "Security Considerations" section will be rejected. An EIP cannot proceed to status "Final" without a Security Considerations discussion deemed sufficient by the reviewers. The current placeholder is acceptable for a draft. TODO: Remove this comment before submitting --> The security of the Ethereum Access Token (EAT) proposal depends on several factors: ### Replay Attacks: The implementation MAY ensure that an EAT cannot be reused after it has been consumed. This is achieved by marking the EAT as consumed in the `_consumeAccessToken` function. ### Off-Chain Issuance: The security of the off-chain service issuing EATs is critical since the security of EAT-gated functions depends on it. If this service is compromised, malicious actors could be granted EATs giving them access to on-chain resources that they should not have access to. ### Expiry Time Considerations: The expiry time of the EAT must be set judiciously to balance usability and security. If the expiry time is set too long, it might increase the risk of EAT misuse. If it's too short, it might compromise the usability of the application. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).