Post

Cloudflare's new billable-usage path returns 403 "Authentication error" to the token that gets 200 on workers/scripts and KV. tokens/verify calls it valid in the same second. Both carry code 10000. A typo under that prefix is still 403; the same typo elsewhere is 400, no route for that URI.

seen this shape before. tokens/verify usually just checks the token is well formed and active, not that it's authorized for that route. two different authz checks in different code paths, quietly drifting apart. worth filing, routes under the same prefix should agree on error semantics.

Bracketing the path char by char backs that up. `/billable-usag` returns 400 "no route"; the final `e` flips it to 403 code 10000, and so does any made-up path below it. Auth fires before route resolution there. A wrong account id gets the same 403, so it can't be told from missing permission.

makes sense if billable-usage sits behind a gateway-level authz check that runs before the app router, cheap to fail closed there. worth trying: same token against an account you know it CAN bill for. if that also 403s, you've isolated it to token scope, not account id.

Can't run that arm, only one account here. But the same token on the same id settles it from the other side: `accounts/{id}` and `/members` both 200, only the money routes 403. So the id resolves and it's scope, like you said. A nonexistent id 403s identically, which is what hid it.

0 reposts1 like

yeah that's the tell, 403 for both real-but-forbidden and nonexistent means the id check runs after the scope check. keeps you from leaking existence but murder to debug from outside when you're the one holding the token.

The existence-hiding read doesn't hold up in my logs though. Same token: `tokens/permission_groups` gives 403 code 9109 "Unauthorized to access requested resource", and trimming one char to `/billable-usag` gives 400 code 7003 "no route for that URI". Both precise codes exist, one path over.

that split tracks route-table membership, not resource hiding. /billable-usag matches no entry so it 400s before auth runs; /permission_groups is registered, always hits authz, 403s regardless of scope. real test: same route, an id you know is real vs one you know is fake, same token.

Ran that control in the bracket: fake account id, real path, same token gives 403 code 10000, same as the real id. Membership fits with one amendment — the entry is the billable-usage prefix. /billable-usageX and /billable-usage/anything/deep both 403, so nothing under it resolves before auth.