Implementing Session Keys with ERC-4337: Scoped Permissions, Step by Step

A game that asks for your seed phrase is not a game. It is a handover. Session keys ERC-4337 exist so you can give an app a pen that only writes inside one box, for a set amount, until a clock runs out. The master key stays in your passkey, hardware wallet, or owner module.

The catch is that ERC-4337 does not ship this feature. The standard gives a smart account a custom validateUserOp. Session keys are whatever that account, or a module on it, decides to accept. ZeroDev, Biconomy, Alchemy, and a Kernel plugin can all call the result a session key and still enforce different rules. If you copy a snippet from one stack into another, you did not implement permissions. You implemented a hope.

What you are actually granting

A session key is a second signer. Usually a fresh secp256k1 key, sometimes a passkey. The account stores a link between that public key and a policy. Later UserOperations signed by the session key pass validation only if the policy still matches.

The owner signs once to install that policy. After that, the app can submit calls with the session key and the user does not see a popup. That is the product. It is also the risk. A silent signer is only safe if the silent part is narrow.

Typical scope, and the minimum I would ship:

  • A target contract, not «any contract.»
  • A function selector, not «any function on that contract.»
  • A token and a cumulative spend cap, in token units, not a dollar estimate from a frontend.
  • validAfter and validUntil as unix seconds. Zero means never expires. Do not leave it at zero.
  • A chain id. A session opened on Base should not replay on Ethereum.
  • A revocation id the owner can kill without rotating the master key.

Alchemy’s permission types make the same cut in product language: an ERC-20 transfer allowance, access to one contract, access to specific functions on the account. Biconomy’s Smart Sessions split it into action policies, including a universal policy that can match a calldata argument and a timeframe policy. ZeroDev’s older session-key validator takes validUntil, validAfter, and an optional paymaster. Different APIs, same job.

The setup, in the order that matters

Start with the account, not the key. The account has to be a smart account on an ERC-4337 EntryPoint, with a validation path that can read a session module. On modular accounts that is usually an ERC-7579 or ERC-6900 module. If the account cannot install one, you are not adding a session key. You are asking the owner to sign every call.

Generate the session key on the device that will use it. A browser game keeps it in memory or local storage. A trading agent keeps it on the machine that submits orders. The owner device never needs the private key. It only needs the public key, so it can authorize that signer.

Have the app declare the scope before the user signs. Target, selector, token, cap, expiry, chain. Show that list in plain language. «This key can call supply on this Aave market, up to 500 USDC, for 24 hours, on Base» is a review screen. «Enable session» is not.

The owner signs the enable transaction with the master key, passkey, or hardware signer. That UserOperation installs the module if it is missing, then writes the permission. Gas can be sponsored by a paymaster. Sponsorship does not widen the scope. It only pays for the install.

From then on the app builds the calldata, wraps it in a UserOperation, and signs with the session key. The bundler submits it. EntryPoint calls validateUserOp. The module checks the signer, the clock, the target, the selector, and the running spend. If any check fails, the op never executes. If they pass, the call runs as the account.

Kill it on a timer and on a button. Expiry is the backstop. Revocation is what you use when the app is compromised at hour two of a twenty-four-hour window.

Where scoped permissions stop being scoped

The wide selector is the usual hole. Allowing every function on a router looks convenient and includes approve, sweep, and whatever admin method the router grew last month. Name the selector. If the app needs two calls, grant two actions, not the contract.

Value limits fail when they are checked in the frontend. The cap has to live in the module, as a cumulative counter, in the token’s own decimals. A per-click limit without a total is a faucet. An allowance that also covers approve is a blank check, because the approved spender can pull later, outside the session.

Delegatecall should be off. A session key that can delegate into an arbitrary contract can replace the rules that were supposed to contain it.

Storage of the session key is the other half. Local storage in a browser extension is a session. A key you upload to your backend so «the bot can trade» is a hot signer you now operate. If that server is popped, the scope is the blast radius. Make the scope small enough that you can stand the loss, then rotate.

EIP-7702 does not replace this. It lets an EOA point at smart-account code for a transaction, so a normal key can temporarily behave like an account with modules. The session policy is still your code. Native account abstraction on newer stacks, including Base’s EIP-8130 work, is pushing the same idea down into the chain: an actor with scope flags, spend limits, and an independent revoke. The user-facing rule does not change. One signer, a written box, a clock.

A setup I would actually approve

For a consumer app, one session, one chain, one contract, two selectors at most, a spend cap under what the user keeps in that account, expiry inside 24 hours, no delegatecall, revocation in the same screen that created the key. Games can stretch the clock if the only allowed call is an in-game action with no token movement. Trading bots should not. A bot session is a budget, not a login.

Before you turn it on, send three UserOperations that must fail: the right call one second after validUntil, the right call to a contract you did not list, and a transfer one unit over the cap. If any of those land, the module is decorative.

Session keys are how ERC-4337 stops feeling like a wallet popup. They are also how a sloppy allowlist becomes a quiet drain. The master key is not what you protect in the session. The policy is.

FAQ

Are session keys part of ERC-4337? No. ERC-4337 lets the account define validation. The session key is a module or wallet feature on top of that.

Can a session key move the whole balance? Only if you allowed it. A correct policy rejects calls outside the target, selector, token, and remaining cap.

What happens at expiry? New ops signed by that key fail validation. Already executed calls stay executed. Revoke if you cannot wait for the clock.

Is a session key safe to put on a server? It is as safe as its scope. Treat the server as compromised on day one and set the cap accordingly.

Educational content only. Not a security audit and not financial advice. Module behavior differs by wallet and EntryPoint version. Test the failing cases on the account you will actually ship.

Investors Planet
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: