Idea
Make creating an anonymous account cost the caller measurable CPU. The server issues a nonce and a difficulty, the client finds a value whose hash meets it, the server verifies in microseconds. Hashcash, essentially — Altcha and mCaptcha are self-hostable implementations of the same thing.
Not urgent. Filing it so the reasoning isn't lost.
Why this endpoint rather than login
Everywhere else already has a cheaper defence. Password guessing is bounded per-account (#725), and creating an account with an email is bounded by the invite code and the confirmation step. add_anon_user is the one path where the rate limit is doing the whole job on its own — see #583 for the other half of why.
It is also the practical choice:
- One endpoint.
- Only reached from clients we ship — web, iOS, Android, extension — so there is no third-party integration to break.
- No legitimate user creates anonymous accounts in bulk, so the challenge can be unconditional. Nothing has to decide whether a caller looks suspicious, which is the part that usually goes wrong.
Constraint: the client has to be the one paying
The tempting version is to make the server slow — sleep on failure, more bcrypt rounds, exponential backoff. That would be worse than doing nothing. The API runs 2 gunicorn workers, kept that low because each holds ~6GB of models, so anything that ties a worker up turns a nuisance into an outage. This only helps if the cost lands on the caller and verification here stays O(1).
To decide
- Difficulty. Has to be trivial on a mid-range phone and a school Chromebook while still biting in bulk. Probably calibrate to something like half a second on the slowest device we care about, and make it a config value rather than a constant.
- Build or adopt. Altcha is self-hostable with a JS widget; hand-rolled hashcash is maybe 100 lines, but that's 100 lines times four clients.
- Client coverage. Any client that doesn't implement it is a way round it, so this ships everywhere or nowhere. That's the real cost of the idea.
- Scope. Whether
add_user wants it too, or whether the invite code plus email confirmation already cover that.
Worth being honest about
Proof-of-work taxes the weakest device hardest — a student on an old school Chromebook does the same work as somebody with a rented GPU, and minds it more. That asymmetry is exactly why it belongs on the one endpoint no real user hits repeatedly, and not on anything a classroom touches.
Idea
Make creating an anonymous account cost the caller measurable CPU. The server issues a nonce and a difficulty, the client finds a value whose hash meets it, the server verifies in microseconds. Hashcash, essentially — Altcha and mCaptcha are self-hostable implementations of the same thing.
Not urgent. Filing it so the reasoning isn't lost.
Why this endpoint rather than login
Everywhere else already has a cheaper defence. Password guessing is bounded per-account (#725), and creating an account with an email is bounded by the invite code and the confirmation step.
add_anon_useris the one path where the rate limit is doing the whole job on its own — see #583 for the other half of why.It is also the practical choice:
Constraint: the client has to be the one paying
The tempting version is to make the server slow — sleep on failure, more bcrypt rounds, exponential backoff. That would be worse than doing nothing. The API runs 2 gunicorn workers, kept that low because each holds ~6GB of models, so anything that ties a worker up turns a nuisance into an outage. This only helps if the cost lands on the caller and verification here stays O(1).
To decide
add_userwants it too, or whether the invite code plus email confirmation already cover that.Worth being honest about
Proof-of-work taxes the weakest device hardest — a student on an old school Chromebook does the same work as somebody with a rented GPU, and minds it more. That asymmetry is exactly why it belongs on the one endpoint no real user hits repeatedly, and not on anything a classroom touches.