{"revision":"0ed62d2c742f8e20","language":"en","entry":{"id":"message-verification","group":"guides","kind":"guide","title":"Verify a signed message","summary":"Check the exact text, its signing key and that key’s state.","sections":[{"kind":"paragraph","text":"A person signs text from the Sign a message tab on their card. They can copy a signature block into a post, announcement or email. Your app sends that whole block to POST /v1/verify."},{"kind":"code","language":"shell","code":"curl -fsS 'https://veil.rip/v1/verify' \\\n  --json @signed-message.json"},{"kind":"paragraph","text":"The JSON file contains a block field with the pasted text. You may add at in Unix seconds. Block mode cannot be combined with key, message, signature, platform or subject."},{"kind":"heading","text":"Read the verdict"},{"kind":"paragraph","text":"Use valid for the overall result. signatureOk checks the bytes of the signature. keyState says whether the key could sign at the chosen time. A signature can still match after its key has been revoked, while valid is false for the current time."},{"kind":"paragraph","text":"Use a publication time from a source you trust when passing at. A date written by the signer does not prove when a message was published."},{"kind":"heading","text":"Check the account too"},{"kind":"paragraph","text":"Raw-signature mode accepts key, message and signature. Add platform and subject together to ask whether that identity held the sending account at the selected time. For a bot, use the platform’s stable account ID."},{"kind":"heading","text":"Keep the message in the browser"},{"kind":"paragraph","text":"The /verify page can read a signature block from the URL fragment or from pasted text and check it locally. Fragment data after # stays in the browser. A /v/ link sends its message to the server so the link can have a social preview. Calling the verification API also sends the message to the server."},{"kind":"heading","text":"Build a sharing link"},{"kind":"paragraph","text":"Use the original message and signatureBytes from the signer. cardNumber is the permanent card number. The browser link supports both signature algorithms. Use the preview link only for Ed25519 and a message of at most 1500 UTF-8 bytes."},{"kind":"code","language":"javascript","code":"function base64url(bytes) {\n  return btoa(String.fromCharCode(...bytes))\n    .replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n}\nconst messageData = base64url(new TextEncoder().encode(message));\nconst signatureData = base64url(signatureBytes);\nconst browserLink = `https://veil.rip/verify#u=${cardNumber}&m=${messageData}&s=${signatureData}`;\nconst previewLink = `https://veil.rip/v/${cardNumber}/${signatureData}?m=${messageData}`;"}],"related":["verify-message","verify-page","verify-link","proofs"],"errors":[],"documentationUrl":"https://veil.rip/docs/message-verification"}}