Bootstrapping the First Admin Without a Back Door
Admins can create admins. Fine — except there are no admins yet. Something has to grant the first one.
The tempting shortcut
"Allow the write if no admins exist yet." One clean rule, self-service setup, no console work.
It is also a race. Between deploying rules and creating your account, anyone who finds the project can claim it. The window is small and the loss is total.
The boring, correct answer
match /admins/{uid} {
allow get: if request.auth != null && request.auth.uid == uid;
allow list, write: if false;
}
Nothing on the client can write here. Ever. You seed one document by hand in the console, where access is governed by IAM instead of your rules.
Thirty seconds of clicking, once, in exchange for a property worth stating plainly: a stolen admin session cannot create more admins. An attacker can vandalize content. They cannot lock you out of your own project.
Why get, not list
allow get on your own uid lets the app answer "am I an admin?" without exposing who else is. list would leak the whole roster to anyone signed in.
When to relax it
When adding people becomes routine. Until then you are trading a hard boundary for convenience you use twice a year.