Stuck on HTTP signatures

Ok, I’m stuck at the http signatures bit. I’m trying to reply to a toot I made and I just get a 401 Unauthorized response, not very informative!

I’m pretty sure I’ve got (almost) everything right, the code is based on this nice simple example:

Should this still work?

Here’s what I’m POSTing to the remote server inbox via fetch() options (based on the Ruby example above):

{
  method: 'POST',
  headers: {
    Host: 'toot.io',
    Date: 'Thu, 21 Dec 2023 04:40:16 GMT',
    Signature: 'keyId="https://skirmish-dev.net/users/marksibly",headers="(request-target) host date",signature="SDKa6ckF2lJ1B0DL7Lk5E6PXJ8dEeE0zOgnl/x6YEbY19AsX2Ix4uZ91hj4q5gYJ3FDzRbh9z7/QW4H3vMbUBRx8lJNeo2PFlCoPFsCEt1C6TupBs2h900ROTfvLO1CJoa3vfF/6E2NpjX3JfuZu1ZU3h30BOpxVhy6oZZPJjqcpMsVGLXgRC7dRfvNk5LE+kSUdX7yfhVTaKPSuEfxN/giEb0WHCoRp6XVPAzjkL2M6rtmcyhIMlj8+jgvhSp4E8wtZ355Uik0isPj2aXTFxU5qexvFbaPcQeE7/XcOYq+uxsmTpvb5O2TnfGMRzOv9x16RjDPq8RY5MqrurhzNDg=="'
  },
  body: '{"@context":"https://www.w3.org/ns/activitystreams","id":"https://skirmish-dev.net/users/marksibly/notes/123/activity","type":"Create","actor":"https://skirmish-dev.net/users/marksibly","object":{"id":"https://skirmish-dev.net/users/marksibly/notes/123","type":"Note","published":"Thu, 21 Dec 2023 04:40:16 GMT","attributedTo":"https://skirmish-dev.net/users/marksibly","inReplyTo":"https://toot.io/users/marksibly/statuses/111603479196881233","content":"Hello there!","to":"https://www.w3.org/ns/activitystreams#Public"}}'
}

Here’s the body, ie: the create note activity:

{
  '@context': 'https://www.w3.org/ns/activitystreams',
  id: 'https://skirmish-dev.net/users/marksibly/notes/123/activity',
  type: 'Create',
  actor: 'https://skirmish-dev.net/users/marksibly',
  object: {
    id: 'https://skirmish-dev.net/users/marksibly/notes/123',
    type: 'Note',
    published: 'Thu, 21 Dec 2023 04:40:16 GMT',
    attributedTo: 'https://skirmish-dev.net/users/marksibly',
    inReplyTo: 'https://toot.io/users/marksibly/statuses/111603479196881233',
    content: 'Hello there!',
    to: 'https://www.w3.org/ns/activitystreams#Public'
  }
}

Here’s the signature before it gets signed and base64-ized.

{
(request-target): post /users/marksibly/inbox
host: toot.io
date: Thu, 21 Dec 2023 04:40:16 GMT
}

I’m using crypto.verify to check my crypto.sign works.

Any hints on how to debug this stuff, it’s driving me a bit nuts! Would installing a mastodon server locally help?

A bit more info, here are the headers actually being sent by node.js fetch:

POST /users/marksibly/inbox HTTP/1.1
host: toot.io
connection: keep-alive
Content-Type: application/ld+json
Date: Thu, 21 Dec 2023 08:08:24 GMT
Signature: keyId="https://skirmish-dev.net/users/marksibly",headers="(request-target) host date",signature="oZsaxeQrLeP6AJJA40IroR9Hkg8INMDsNBH8npe1XUkaIfeKK4rpqLyajxeNgyRS7FKAqqvVj7by0W/GKElVrrV0gS3YOQc6ksyy5DZqwRXrqD1LPcK7TECmYz4rncYc9E2JoN7n3Afo3oHkhKJqNzqmqcPsdtJrrtQBxSo+O01jUN+HUFeMCUa0t6XigCpANjVAx3/lX7Q+NfZ/0c3fuwkF57uUhj+eU0WjGGuYVDDAWOmua0ORC5sQ3Vij6m6WyUoBsivghV52DxIfFakVaxhcG2kxDEt/N96B8wRfNY0NZSPTkTqef+MQforhgY4FUBLOY+iYdx/wVIDn8Z415Q=="
accept: */*
accept-language: *
sec-fetch-mode: cors
user-agent: node
accept-encoding: br, gzip, deflate

The server I’m trying to post to isn’t even requesting my actor/public key so it must be failing before it even tries to verify the signature?

Note: if you’re using the new ‘native’ fetch in node.js, you can use this to log requests and responses:

import diagnosticsChannel from "diagnostics_channel";

diagnosticsChannel.channel('undici:client:sendHeaders').subscribe(({ request, headers, socket }) => {
	console.log(headers);
});

diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, response }) => {		
	console.log(response.statusCode, response.statusText);
});

More info here: https://github.com/nodejs/undici/blob/c5c6648a7d2097f9be4d1f7d06df9f158eff049d/docs/api/DiagnosticsChannel.md

I can’t contact your server at all:

$ nc skirmish-dev.net 443
skirmish-dev.net [121.99.175.55] 443 (https) : No route to host

Hi,

The server isn’t currently up 24/7, it’s basically just an ‘old PC on the kitchen bench’ style setup…

I didn’t think it’d be necessary as the remote server never even seems to be attempting to connect back, but I guess it could well be something to do with my server config or routing or whatever that I know absolutely nothing about so I’ll leave it running while sorting this out.

The server can really only handle webfinger and actor requests, eg:

https://skirmish-dev.net/.well-known/webfinger?resource=acct:marksibly@skirmish-dev.net

…and…

https://skirmish-dev.net/users/marksibly

(with or without .json extension, not sure if it’s required)

However, this is enough to be able to ‘find myself’ on mastodon which is cool!

Bye,
Mark

Fixed: 202 Accepted!

You also need to add a ‘digest’ header for POSTs, as docced here:

So the example is buggy I think. Once I learn how to edit Wiki Posts, I’ll add a note to the ActivityPub.Rocks page.

the example is from a blog post in 2018 and was never updated. add digest to deliver.rb by jakekara · Pull Request #1 · mastodon/blog · GitHub is a PR that would update it.

the additional requirements were added to mastodon v3.3 in 2020 Add support for latest HTTP Signatures spec draft by ClearlyClaire · Pull Request #14556 · mastodon/mastodon · GitHub

1 Like