WHEN IT FAILS

Revoke a session

The key lives in sessionStorage so a refresh is free. Any script on the page can read it.

The key and its grant are stored together in sessionStorage, keyed by app, chain and granter. That is why a refresh is free. It is also why any script on the page can read a real key. An XSS hole means an attacker can call play as your user until the grant expires.

withSession is not payable, so a stolen key cannot move value, and it only reaches the selectors the grant named. That bounds the damage. It does not remove it. Scope tightly. Expire sooner if the action is expensive even without value.

Kill every grant this user has signed

lib/interlude.ts
import { memoryStore } from "@interludelayer-sdk/sdk";

createInterludeClient({ app, abi, node, base, store: memoryStore() });

// Every grant this user has ever signed, for every Interlude app, dead.
await interlude.revokeAll(wallet);

revokeAll bumps the hub epoch on Monad. Every existing grant names the old one, so the next call reverts with SessionEpochStaleError. The user signs again if they still want to play. memoryStore() keeps the key in RAM for that tab only: a refresh now prompts, and a script in another tab sees nothing.

There is no localStorage option. A key that outlives the tab is a key nobody remembers granting. Sessions expire in an hour unless you pass a shorter ttl to openSession.