Invalid Signature Webhook with Remix

I am having an issue with invalid signatures. Iโ€™m working with remix.run.

    const payload = await request.json();
    const signature = request.headers.get('x-signature');

It is getting the signature fine, but telling me the signature is invalid.

Moralis.Streams.verifySignature({
  body: payload,
  signature: signature,
});

The error I am getting is:
MoralisError [Moralis Stream Error]: [S0004] signature is not valid

How do you validate the signature?

As shown above, with the Moralis.Streams.verifySignature() function. I have also tried implementing it myself as seen below:

    const providedSignature =request.headers.get('x-signature');
    if(!providedSignature) throw new Error("Signature not provided")
    const generatedSignature= web3.utils.sha3(JSON.stringify(payload)+process.env.Moralis_Web3_Api_Key)
    if(generatedSignature !== providedSignature) throw new Error("Invalid Signature")
}

and the issues are always around the generated signature not being equivalent to provided Signature.
Thanks so much for your time!

here try to use the raw payload data that you received instead of trying to convert it from an object to a string

there you will also find an example in python to generate that signature:

Hi, thanks for your help.
I have tried this already and it unfortunately does not work.

can you give a full example that doesnโ€™t work? with the raw request that you received and the signature?

I mean, can you paste here on forum the payload and the signature?

Sure, and thank you so much again for your help!

Payload:

{
  confirmed: true,
  chainId: '0x1',
  abi: [
    {
      anonymous: false,
      inputs: [Array],
      name: 'Transfer',
      type: 'event'
    }
  ],
  streamId: '8d40b4d7-cac8-4799-9c92-2a373515d5c2',
  tag: '  ERC721s',
  retries: 0,
  block: {
    number: '16570335',
    hash: '0xd3bfb13d99d0f4e2533b4c66cdd714a37434a7442327f1d6a429164be49c9c03',
    timestamp: '1675693595'
  },
  logs: [
    {
      logIndex: '301',
      transactionHash: '0xd800ab4cbc3c1c0a6b2392445d9e6bfe98df7162d3c9671a15e4ff0dddb126a2',
      address: '0x8a90cab2b38dba80c64b7734e58ee1db38b8992e',
      data: '0x',
      topic0: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
      topic1: '0x000000000000000000000000e301b3d8d6bc4ef014d66eb73f805fbbb9bc44a2',
      topic2: '0x000000000000000000000000728b3de78c3bd3e9c970524ca6aae1f8d6a61996',
      topic3: '0x0000000000000000000000000000000000000000000000000000000000000118'
    }
  ],
  txs: [],
  txsInternal: [],
  erc20Transfers: [],
  erc20Approvals: [],
  nftTokenApprovals: [],
  nftApprovals: { ERC721: [], ERC1155: [] },
  nftTransfers: [
    {
      operator: null,
      from: '0xe301b3d8d6bc4ef014d66eb73f805fbbb9bc44a2',
      to: '0x728b3de78c3bd3e9c970524ca6aae1f8d6a61996',
      tokenId: '280',
      amount: '1',
      transactionHash: '0xd800ab4cbc3c1c0a6b2392445d9e6bfe98df7162d3c9671a15e4ff0dddb126a2',
      logIndex: '301',
      contract: '0x8a90cab2b38dba80c64b7734e58ee1db38b8992e',
      tokenName: 'Doodles',
      tokenSymbol: 'DOODLE',
      tokenContractType: 'ERC721'
    }
  ],
  nativeBalances: []
} 

signature:

0x95d3f428aaef5ee34cd4d833340c3350be926be0ddc85a232bdbb3315d4102be

I need the payload in a string format, not as an object, the original payload data that you received

This is the request:

  size: 0,
  follow: 20,
  compress: true,
  counter: 0,
  agent: undefined,
  highWaterMark: 16384,
  insecureHTTPParser: false,
  [Symbol(Body internals)]: {
    body: ReadableStream3 [ReadableStream] {
      _state: 'closed',
      _reader: [ReadableStreamDefaultReader2 [ReadableStreamDefaultReader]],
      _storedError: undefined,
      _disturbed: true,
      _readableStreamController: [ReadableStreamDefaultController2 [ReadableStreamDefaultController]]
    },
    type: null,
    size: null,
    boundary: null,
    disturbed: true,
    error: null
  },
  [Symbol(Request internals)]: {
    method: 'POST',
    redirect: 'follow',
    headers: {
      accept: 'application/json, text/plain, */*',
      'accept-encoding': 'gzip',
      'content-length': '4223',
      'content-type': 'application/json',
      host: 'cceb-151-237-238-179.ngrok.io',
      'user-agent': 'axios/0.27.2',
      'x-forwarded-for': '18.157.94.22',
      'x-forwarded-proto': 'https',
      'x-queue-size': '0',
      'x-records-charged': '0',
      'x-region': 'eu-central-1',
      'x-signature': '0x647112ef8ff1f6d644951a6f796adfa4ce7b3855bd3b9f576d1e45fe4948016f'
    },
    parsedURL: URL {
      href: 'http://cceb-151-237-238-179.ngrok.io/webhook',
      origin: 'http://cceb-151-237-238-179.ngrok.io',
      protocol: 'http:',
      username: '',
      password: '',
      host: 'cceb-151-237-238-179.ngrok.io',
      hostname: 'cceb-151-237-238-179.ngrok.io',
      port: '',
      pathname: '/webhook',
      search: '',
      searchParams: URLSearchParams {},
      hash: ''
    },
    signal: AbortSignal {}
  }
}

This is the corresponding signature:

this is still an object, the raw request is a string, only a string, without any other interpretation

I have stringiyd it for you, but the above is the format of the request that is returned for a request in Remix.run.

{"confirmed":false,"chainId":"0x1","abi":[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"}],"streamId":"8d40b4d7-cac8-4799-9c92-2a373515d5c2","tag":"  ERC721s","retries":0,"block":{"number":"16570547","hash":"0xe44cf4dbbe795600eb76c0b788bae62d19facdeca5980a7e204f1e1b18ef788d","timestamp":"1675696175"},"logs":[{"logIndex":"207","transactionHash":"0x404775edfe2a66ddd0b1d20f752eb620c9f41defe71e2e9d60822e1197e95596","address":"0x1a92f7381b9f03921564a437210bb9396471050c","data":"0x","topic0":"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","topic1":"0x000000000000000000000000127ecf853f7c0d59e415a28354e482fd41604b4f","topic2":"0x0000000000000000000000006b024fa47e2a77b0a670fb89103b9055fb061b97","topic3":"0x0000000000000000000000000000000000000000000000000000000000001c30"}],"txs":[],"txsInternal":[],"erc20Transfers":[],"erc20Approvals":[],"nftTokenApprovals":[],"nftApprovals":{"ERC721":[],"ERC1155":[]},"nftTransfers":[{"operator":null,"from":"0x127ecf853f7c0d59e415a28354e482fd41604b4f","to":"0x6b024fa47e2a77b0a670fb89103b9055fb061b97","tokenId":"7216","amount":"1","transactionHash":"0x404775edfe2a66ddd0b1d20f752eb620c9f41defe71e2e9d60822e1197e95596","logIndex":"207","contract":"0x1a92f7381b9f03921564a437210bb9396471050c","tokenName":"Cool Cats","tokenSymbol":"COOL","tokenContractType":"ERC721"}],"nativeBalances":[]}

signature:

0xa8c7216ece7e46c4ba62ed1bdd89e0258b801e5635b1e42a96b1cfab13a94a40

I got this signature for that string and with your api key:

0x03df83cd2a72a56d12582e59cafb60c07f3a68c15b0054af38c8a01204e71b13 

yep, and 0xa8c7216ece7e46c4ba62ed1bdd89e0258b801e5635b1e42a96b1cfab13a94a40 is the one moralis sends which is not the same

Maybe something else happens. Do you have access to the raw response body?

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.