@chipi-stack/backend (14.16.0+) ships both halves:
createStarknetSignInTypedDatabuilds the message.verifyStarknetSignInchecks it: chain, domain, URI, nonce, expiry, and the signature.
is_valid_signature) and with accounts that are not deployed yet, which is how new Bramble and Ready accounts start out.
1. Issue the message (server)
Store the nonce with a short expiry, then return the typed data to the browser.SN_MAIN in the domain, and single-line printable ASCII strings. It throws on anything else, because some wallets (Bramble among them) refuse to sign it.
2. Sign it (browser)
Any Starknet wallet signs it through the standard wallet API:ACCOUNT_NOT_DEPLOYED, also send the wallet’s deployment data:
3. Verify (server)
Consume the nonce (once, atomically), then verify:
The typed data is rebuilt from its message before hashing, so a client can’t swap in extra types or a testnet domain. Only
'VALID' counts as valid: accounts answer 0 or revert on a bad signature, and a looser “anything non-zero” check would accept garbage.
Undeployed accounts are supported for OpenZeppelin 3.0 (Bramble’s default account) and Argent 0.4 without a guardian (Ready). Other undeployed accounts get UNSUPPORTED_ACCOUNT_CLASS: ask the user to make one transaction first, which deploys the account.
Lower-level helpers
isValidStarknetSignature(provider, address, hash, signature)asks any deployed account about any message hash.verifyUndeployedStarknetSignature(deploymentData, hash, signature)does the off-chain check on its own.
Related
✅ Verified against the SDK source on 2026-10-10.
