A production walkthrough of the auth pattern powering CoinHawk's admin layer β and why "the client says they're 0xABC" is a security bug. The naive way (and why it's broken) When a user connects MetaMask to your dapp, the browser hands you their wallet address through window.ethereum.request({ method: "eth_requestAccounts" }) . Tempting flow: Frontend asks MetaMask for the address Frontend POSTs { address: "0xABC..." } to your backend Backend stores it on the session Backend uses that address to gate admin features, route fees, log trades, etc. This is completely insecure . Anyone with curl can POST any address they want. There is zero proof the requester controls the private key for 0xABC . They could claim to be Vitalik. They could claim to be your admin wallet. You need a proof of ownership step. The standard solution is a signed-nonce challenge β and it's surprisingly easy to get wrong if you trust the client for any of the inputs. Here's the pattern I shipped in CoinHawk, with the real production code.β¦