What Todoke can and can't see in your GitHub account
Todoke is an issues client. It cannot read your code, and the permission set is the reason rather than a promise. I have written down exactly what it asks for, what I tried first and threw away, and why signing in still costs you two GitHub screens.
The permission set, in full
Todoke is a GitHub App, not a personal access token and not an OAuth App. You can read the whole permission list yourself on its GitHub App page before installing anything. It is short:
- Issues — read and write. This is the app. Open, edit, comment, label, assign, close, reopen.
- Metadata — read. Mandatory on every GitHub App; GitHub does not let you turn it off. It covers repository names, labels, milestones and collaborators. It does not cover file contents.
- Pull requests — read. GitHub's issues API returns pull requests in the same list as issues, because on GitHub every pull request is an issue. Todoke filters them out of the feed client-side; the read permission is what makes filtering them possible rather than showing them to you.
And the two that matter by their absence: no repository administration, and no organization-level permission. That is not only a privacy line. An app that asks for neither can be installed by a plain repository admin, while an app that asks for either dead-ends on an organization owner's approval queue. The narrow permission set is also the reason installing Todoke on a work repo usually just works.
Why GitHub asks you twice
Installing and authorizing are two different things on GitHub, and Todoke needs both. The installation is what grants access to the repositories you pick. The authorization is what identifies you, so a comment Todoke posts is posted as you and not as a bot.
Two consent screens is GitHub's floor and no app can remove it. A user token cannot write to a repository that no installation covers, so both have to happen.
What an app can remove is asking twice across two separate trips to the browser. My first version did not. Counting the screens I shipped: a sign-in wall, a bare "Checking your GitHub access…" spinner, a second full screen asking you to install a GitHub App on your repositories, another spinner, and a "Connected" hub with a Continue button. Five of my screens and two browser round-trips before anyone saw a single issue.
Three separate things were wrong with it, and I only understood the third one late. The second screen was a surprise, so people read it as being asked for permission twice. The spinners explained nothing, so they read as the app hanging. And "install" is a frightening word when it arrives without context — I had used GitHub's vocabulary instead of explaining what was about to happen.
Today it is one trip. Todoke opens the install page first, you pick repositories, and the flow continues straight into authorization inside the same browser sheet. Two GitHub screens, one trip, none of mine in between.
How that is actually done, since GitHub doesn't document it
GitHub preserves the state parameter from an installation URL all the way through to the app's Setup URL. Todoke's Setup URL is a small stateless service we run, so that service can read the state and redirect into the authorization URL — and the redirect happens inside the browser sheet that is already open.
That rests on an assumption GitHub documents nowhere: that the authentication session follows the redirect without dropping the sheet, and then ends on the app's callback. It does, and I could not find anyone who had written that down, which is most of why this page exists.
I could not prove it in a test either. Nothing in the suite can cover a hop that happens inside a system browser sheet, so I checked it the only way available: a physical iPhone, a fresh install, build 5, on 30 July 2026, tapping Get Started and counting how many times GitHub asked. Twice, which is the floor. If this ever needs re-checking, that is the whole procedure.
The authorization uses PKCE, so the secret half of the exchange never leaves your phone. Todoke also never trusts the installation id GitHub hands back; it re-checks it against your own account's installation list using your own token, because a value that arrives through a redirect is a value an attacker can suggest.
Two designs that would have been easier, and are worse
"Request user authorization during installation." GitHub offers a checkbox that collapses the trip for you. It builds the authorization URL with the client id alone — no redirect target, no state, and no place to attach a PKCE challenge — and it is mutually exclusive with using a Setup URL at all. It trades the security property for the convenience.
A classic OAuth App. This skips installation entirely, which sounds better until you read what it costs: the only scope that permits writing issues is repo, which grants full read and write on every private repository you can reach, source code included. An app that promises it cannot read your code, implemented in a way that grants it the ability to read all of it, is not a promise. It also creates more friction inside organizations, not less.
I tried the checkbox first, because it is obviously the easy answer, and gave it up when I went looking for where to attach the PKCE challenge and found there was nowhere. The OAuth App route I never built — reading what repo actually grants was enough. Both short paths end with an app that can read your code, so Todoke took the long one.
What Todoke stores
Your GitHub token lives in the iOS Keychain on your device. Issue content is fetched from GitHub when you look at it and is never copied to a server of mine, because there is no Todoke backend to copy it to. The one service I run is the stateless redirect described above. It completes the sign-in exchange and stores nothing, and it is the smallest piece of infrastructure I could get away with.
The full detail is in the privacy policy, and the questions developers actually ask — self-hosted GitHub Enterprise, personal access tokens, offline use — are answered in the FAQ.