veil

Verify a signed message

Check the exact text, its signing key and that key’s state.

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.

cURL
curl -fsS 'https://veil.rip/v1/verify' \
  --json @signed-message.json

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.

Read the verdict#

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.

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.

Check the account too#

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.

Keep the message in the browser#

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.

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.

javascript
function base64url(bytes) {
  return btoa(String.fromCharCode(...bytes))
    .replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
}
const messageData = base64url(new TextEncoder().encode(message));
const signatureData = base64url(signatureBytes);
const browserLink = `https://veil.rip/verify#u=${cardNumber}&m=${messageData}&s=${signatureData}`;
const previewLink = `https://veil.rip/v/${cardNumber}/${signatureData}?m=${messageData}`;