Featured image of post Desktop apps don't paste

Desktop apps don't paste

TikTok's OAuth flow wants you to copy a code out of a web page and paste it into a terminal. What it took to give keryx a native flow instead.

keryx exists because I got tired of being a copy-paste machine. It started as a way to speed up making promo reels for social media, and the more of them I made, the more the actual posting became the slow bit: the same clip and caption, fed by hand into one platform after another, every time. So the natural next step was to stop hand-posting and wire keryx straight into the platforms themselves. TikTok was one of the first I reached for.

My assumption going in was that this would be straightforward, because every major platform has a proper integration story now. There’s an API, there’s an OAuth flow, there’s usually a first-party desktop or mobile app that proves the whole thing works for software that isn’t a website. I was confident TikTok would be no different, and went looking for the clean native flow I was sure existed.

What I found, at first blush, looked like a step backward. The path that presented itself was a hosted callback page: you authorise, the platform redirects to a web page you host, that page shows you a code, and you copy the code back into keryx by hand. It works. People ship it. But pasting a code into a terminal by hand, in 2026, to authenticate against one of the most popular platforms on the planet, felt wrong in a way I couldn’t let go of. It’s the kind of friction keryx exists specifically to remove, and here it was reappearing in the tool’s own setup.

So I dug, mostly out of stubbornness. And the thing I’d missed wasn’t a TikTok detail at all. It was that I’d classified keryx as the wrong kind of OAuth client.

The copy-paste callback is the flow you reach for when you’re a web app: a server somewhere owns the redirect URI, the browser comes back to it, and the code makes its way to you. keryx isn’t a web app. It’s a desktop app running on your own machine, and desktop clients have a flow of their own that web apps don’t get: a loopback redirect. The app spins up a tiny listener on 127.0.0.1, registers that as the redirect, and the platform calls straight back to it on the local machine. No hosted page, no human in the loop, no code to ferry across by hand. The mechanism was there the whole time. I’d just been holding the web-app pattern out of habit and trying to make keryx fit it.

The fix, once I’d seen it the right way round, was almost anticlimactic, because I’d already built it. keryx’s YouTube auth was using exactly this loopback capture. So TikTok got pointed at the same machinery: register the loopback redirect, capture the callback locally, and delete the hosted callback page that had only ever existed to support a constraint that wasn’t real. One client type, one redirect flow, the paste gone.

The whole tangle came down to a question I’d never actually asked: what kind of OAuth client is keryx? Web app, desktop app, single-page app, device with no browser at all, these aren’t shades of one flow, they’re different flows with different rules about who’s even allowed to receive the callback. It’s the same realisation sitting under who holds the client secret elsewhere in keryx’s auth: a lot of OAuth pain is just a tool pretending to be a kind of client it isn’t. I went to the redirect carrying an assumption about my client type I’d never actually examined, and the paste hack was the perfectly logical answer to the wrong question. The platform wasn’t being backward. I was asking it for the web-app flow when keryx had earned the desktop one all along.

Built with Hugo · Theme Stack designed by Jimmy