Let me tell you about the Trello Power-Up we built. The idea is simple: you keep a content plan in Trello, one card is one post, and the card's due date is the publish date. What was left was manual. On the day, someone copied the text out of the card and posted it to each social network by hand. We made it so you can press Publora right inside the card and queue the post to publish automatically on that date.
I should admit up front: I don't write the code, Claude does. I sit next to it, ask questions, and sometimes ask it to double-check something it already considers done. This time, most of our hours went into its idea of using a newer way to authenticate.
We built the whole thing in a day. Read the docs, made a text-only prototype, added images and video, tested across three browsers in light and dark themes. Submitted for review. Atlassian approved the Power-Up in three days, though their docs warn that review usually takes two weeks or more. There are over six hundred Power-Ups in the catalog, and we couldn't find a single one that publishes cards to social.
The authentication, though, took some wrestling.
Modern OAuth couldn't download a file
The Power-Up pulls images from the card's attachments. To fetch them, Claude and I went with Trello's OAuth 2.0. The newer way to authenticate, all by the book.
But the attachment download endpoint kept answering 401: unauthorized permission requested. I even asked for the write scope, though we only needed read. Nothing changed. Claude wanted to keep digging through scopes; I decided to try the old auth instead.
And it worked. Trello's classic key-and-token scheme, with read-only rights, downloaded the same attachments without complaint. It stung a little: we'd set the new auth up straight from the docs, and the file came from the old one.
So we left two ways to authenticate. Publora uses OAuth with PKCE, and downloading Trello attachments uses a key and token with read-only rights. We even left a comment in the code, so that in six months nobody, Claude included, decides it's forgotten legacy that urgently needs replacing:
// The Power-Up's Trello API key (public). Used only to read the card's
// attachments: Trello's OAuth 2.0 tokens are refused by the attachment download
// endpoint ("unauthorized permission requested", checked 2026-10-13, even with
// write scope), while a read-only key/token pair downloads them.
Signing into Trello only asks for read:
var url = "https://trello.com/1/authorize?expiration=never&name=Publora&scope=read&callback_method=fragment" +
"&key=" + TRELLO_KEY + "&return_url=" + encodeURIComponent(location.origin + "/trello-callback");
So we're leaving the old auth alone for now. It does, at least, download files.
Trello hands you a file with no type or size
The next annoyance was smaller. Trello returns an attachment with no mimeType. The file is there, but the API doesn't say what kind of file it is. We had to work out the type from the extension:
var MIME_BY_EXT = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp",
tif: "image/tiff", tiff: "image/tiff", avif: "image/avif", mp4: "video/mp4", mov: "video/quicktime", webm: "video/webm" };
function mimeFor(name) { var m = String(name || "").toLowerCase().match(/[.]([a-z0-9]+)$/); return m ? MIME_BY_EXT[m[1]] || null : null; }
Trello doesn't report the size either, so our bridge works that out.
The file doesn't go through the user
This part I particularly like, and credit to Claude for it. The user doesn't have to download the file from Trello and then upload it to Publora. The file goes straight from Trello into Publora's storage, without being buffered whole in memory. That way even a 150 MB video can go through without hitting the worker's memory limits:
const length = Number(file.headers.get("Content-Length") ?? "0");
const limit = body.mimeType.startsWith("video/") ? 150 * 1024 * 1024 : 25 * 1024 * 1024;
if (length > limit) { await file.body.cancel(); /* 413 too_large */ }
const { readable, writable } = new FixedLengthStream(length);
file.body.pipeTo(writable);
await fetch(slot.uploadUrl, { method: "PUT", headers: { "Content-Type": body.mimeType }, body: readable });
The sequence is: create a draft, get an upload URL, send the file with PUT, call complete-media, and create the post. If anything fails along the way, we delete the draft so we don't leave stray records.
A bug we caught ourselves
We found this one before submitting, while checking the Power-Up against the guidelines.
The post status on a card, Scheduled, Published or Failed, should only be updated by the user who sent the post. Otherwise a board member on a different Publora account could see someone else's card marked Removed. To them the post didn't exist, and they could overwrite the status the author saw.
We fixed it before review. Good thing we tested that case at all: when you test everything under one account, a bug like this is easy to miss.
Review, and the letter F that became A+
Review took three days. On the first round Atlassian came back with one note: HSTS wasn't enabled. The letter said "< 365 days", though their own guidelines ask for at least a year. A typo, presumably.
Since we were back in the security settings anyway, Claude and I went through the whole guide: added headers, set up CSP with no inline scripts, no-store. The securityheaders.com score went from F to A+.
That took another evening. But there were no more notes.
Across the whole project, I don't think I suggested a newer technology even once. That's usually Claude's department. After the OAuth episode, I decided to let it get on with things, just not to agree quite so fast.
What came of it
Publora is in Trello now. From a single card you can schedule a post to ten social networks at once, on the date in the card's due field. Everything happens inside Trello, with no switching between apps.
The Power-Up works on free Trello. It isn't available in the Trello mobile apps, because they don't run third-party Power-Ups. It does work in the mobile browser.
Listing link: [coming tomorrow].
Have you ever picked a newer way to authenticate, and then found the older one handled the job you needed better?

