2026-03-10T05:56:19.022Z
On that note, it's seemingly completely impossible to revoke an OAuth client's refresh token (which can live for up to two years!!!!!!!), because even the client application can't willingly give it up! And Bluesky offers no page to view and revoke your authorized apps! Terrifying!!!
You're literally better off using app passwords that grant total control, but you can revoke them, than OAuth, which you can't take away
How was this deemed ready for production at all???
</rant>
2026-03-10T06:09:03.809Z
Okay, I take ONE thing back. You can revoke OAuth apps as an end user on a Bluesky hosted PDS at https://bsky.social/account , something I had to dig through blog posts to find and is not immediately linked to.
2026-03-10T06:10:17.020Z
And if you operate your own PDS there should be a similar web management page
Still looking for the way a developer is supposed to revoke their own access token though!!!
2026-03-16T20:19:38.215Z
You have got to be kidding me Twitter (now known as X)
Identifying your OWN logged in user costs money now?
Truly degenerate levels of greed
A whopping $0.01 per call too, really? Do you really think your platform is even worth that much?
2026-03-24T17:43:44.456Z
I think Thinkblog was in my dream last night
2026-03-24T17:45:03.283Z
I took a screenshot of something wrong on a website on my computer and was going to paste it into my Thinkblog, but remembered that I had to save it as a file and attach it first, because Thinkblog doesn't yet support pasting in images
And that was basically the end of the dream
2026-03-24T17:46:39.601Z
Dreaming about noted shortcomings and feature requests, now that's something
2026-03-31T22:59:16.572Z
Absolutely ecstatic right now
Plurk and Discogs working in the nick of time (mostly excited about Plurk)
Was worried I wouldn't get that particular flow working in time
2026-04-01T13:35:28.136Z
I love seeing ducks floating in puddles that are just barely large and deep enough to hold them. Like, yeah, you would do that.
Anyway, can finally relax now that everything's deployed for April 1st
2026-04-02T04:33:59.994Z
Congrats to Joey on discovering a novel WebKit bug! One that maybe would have gone unnoticed for a while if not because of Spruce's behavior
2026-04-02T04:35:23.492Z
Here's a normal GET request made by fetch in WebKit:
GET /v4/getannouncement.sjs HTTP/1.1
Host: api.stibarc.com
Accept-Encoding: deflate, gzip, br
Origin: https://stibarc.com
Referer: https://stibarc.com/
Accept: */*
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)
Accept-Language: en-US
And what it gets back:
HTTP/1.1 200 OK
Date: Thu, 02 Apr 2026 04:26:16 GMT
Connection: keep-alive
Content-Length: 15
Content-Type: application/json
Access-Control-Allow-Origin: *
Via: HTTP/1.1 api.stibarc.com (SpruceHTTP/0.4.2)
Server: SpruceHTTP/0.4.2
x-powered-by: SJS
That's good and cool. Congrats to Apple on following the spec there and handling it fine
Now here's a POST request made by fetch in WebKit:
POST /v4/getposts.sjs
Content-Type: application/json
Origin: https://stibarc.com
Referer: https://stibarc.com/
Accept: */*
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/605.1.15 (KHTML, like Gecko)
And what WebKit thinks it sees back:
NaN undefined
Notice anything, uh, missing from the POST request?
That's right, the HTTP/1.1 at the end of the first line!
That's actually super-duper important
2026-04-02T04:38:30.612Z
HTTP before 2 and 3 are plaintext protocols, and depend on the version being at the end of the first line of the request to know what version the client is using. For each version:
HTTP/0.9: GET /
HTTP/1.0: GET / HTTP/1.0
HTTP/1.1: GET / HTTP/1.1
You'll notice HTTP/0.9 completely lacks the version altogether. That's because it's the first!
This is all in the name of backwards compatibility, of course
HTTP/1.0 and 1.1 don't differ too much, except the requirement of the Host header (so the website knows which one the client wants to access)
But HTTP/0.9 doesn't have headers at all\
A normal HTTP/1.1 request is what you see in the first request, but a HTTP/0.9 request looks like this:
GET /
That's it
No extra information can even be provided, because the server stops listening after the first line. You can't do anything except GET requests either
Now, modern day webservers often forgo HTTP/0.9 (and even 1.0 at times) because realistically no client is actually sending 0.9 requests anymore. None would be crazy enough to do it over HTTPS either!
But SpruceHTTP, in the name of ultimate compatibility, actually does allow you to still make 0.9 requests!
So for any other website this bug goes unnoticed, because most server software will ignore the lack of a version string and just assume 1.1 at minimum
But for STiBaRC (and any other Spruce website), it treats this request as the HTTP/0.9 request it claims to be
So it ignores all the headers, and ignores the POST body, and it sends back a 404 page with no response status line (that's the "HTTP/1.1 200 OK" part of the response) or headers. Just the body and nothing else.
Safari, expecting a status line since it thinks it sent a 1.1 request, obviously can't parse <!DOCTYPE html> as anything similar to "HTTP/1.1 200 OK", so it gives up immediately
Therefore, POST requests from fetch have been broken in WebKit for who knows how long, and the problem hasn't been noticeable because most web servers break the HTTP spec these days
2026-04-02T04:54:34.346Z
Further testing does narrow this down to only fetch and not XMLHttpRequest. Interesting.
2026-04-02T05:10:22.638Z
Nevermind, it's also happening there, I have no idea why it worked once
2026-04-02T07:50:40.111Z
Updates: only partially WebKit's fault, partially my fault in Spruce
I did already fix this, but for tracking: https://sprucehttp.com/tickets/bugs/17
Still odd behavior, I might still report the bug about it making HTTP/0.9 requests when stalled for the OPTIONS request to complete
2026-05-15T06:24:58.083Z
Why does Micropub use a single endpoint that handles all operations? It seems like the kind of thing that would greatly benefit from RESTful API design, considering all of the operations you perform using it are against specific RESOURCES.
Create/update/delete operations should not all be handled by POST calls with a different "action" property (and only update/delete have the action property - create doesn't!). Why can I create resources using one of application/json, application/x-www-form-urlencoded, or multipart/form-data content-types, but if it's JSON then I have to check if it's a update/delete? Why not, I don't know, use the PUT and DELETE HTTP methods that are meant for this?
There is seemingly no read operation at all for programmatic access, that's left up to the implementation generating an HTML document that uses the Microformats2 h-* vocabularies, which Microformats2 implementations should just parse the HTML to read entities. What???
Speaking of Microformats2, the Micropub spec depends on it for the different types of resources you can create with it (cards, entries, citations, etc.), and defers to the Microformats2 wiki to explain all of that. The problem is that Microformats2 seems... incomplete? Not all documentation is there, and there's no clear place for you to start getting a grasp of all the concepts. You're just thrown right into it and left to figure it out. Which is not good, to say the least, for a purported specification. Specifications are meant to be complete, self-contained things with formal definition, not a vague list of properties with no validation rules at all.