What it does
- Frontend asks Pylon for a fresh nonce for the user’s address.
- Frontend builds an EIP-4361 message (
Sign in to acme.com\n\nAddress: 0x...\n...nonce: ...\n...) and asks the user’s wallet to sign it viapersonal_sign. - Pylon recovers the address from the signature using secp256k1 ECDSA and Keccak-256 (Ethereum’s variant). It validates the message’s domain, nonce, and expiry, then mints a session keyed on the wallet.
Endpoints
Schema
The user entity needs awalletAddress field:
unique constraint stops two accounts from claiming the same address.
Sign-in flow
1. Request a nonce
2. Build and sign the message
The frontend constructs an EIP-4361 message and asks the wallet to sign it (MetaMask, WalletConnect, Coinbase Wallet, etc.):3. Verify
displayName is optional. Pylon uses it only when it creates a new User row for a first-time address. The default is the short form 0x742d…beb0.
Errors:
Verification details
Pylon validates:- Signature recovery: secp256k1 ECDSA and a Keccak-256 hash of the EIP-191 prefix (
\x19Ethereum Signed Message:\n<len>) followed by the message recover a 20-byte address. It must matchmessage.address, case-insensitive. - Nonce: the nonce must exist in the nonce store, bind to
message.address, and be single-use. Pylon consumes it on first verify. - Domain:
message.domainmust match the request’sHostheader. This stops replay across deployments. - Issued and expiration: if
message.expirationTimeis set, it must be in the future. Ifmessage.notBeforeis set, it must be in the past.
0x742d35Cc... and lowercase 0x742d35cc... addresses resolve to the same User row.
Security guarantees
- secp256k1 and Keccak-256: Pylon uses the
k256crate, the same audited primitives Ethereum uses. - Nonce binding to address: using
nonce-for-Ato sign in as B fails verification. - Single-use nonces: Pylon consumes each nonce on first verify, regardless of success.
- Domain pinning: Pylon validates
message.domainagainst theHostheader and rejects replay across deployments. - Expiration enforcement: Pylon honors
expirationTimeandnotBefore. - EIP-191 prefix: Pylon applies it correctly, which defeats signature reuse from any other Ethereum-signed payload.