title: Cloud Firestore: Enforcing Unique User Names
body: <p><strong>The Problem</strong></p>
  
  <p>I have seen this question several times (also in the context of the Firebase Real-Time Database), but I haven't seen a convincing answer to it. The problem statement is fairly simple:</p>
  
  <blockquote>
    <p><strong>How can (authenticated) users choose a username that hasn't been taken yet?</strong></p>
  </blockquote>
  
  <p>First of all, the <em>why</em>: After a user authenticates, they have a unique user ID. Many web-apps, however, let the user choose a "display name" (how the user wants to appear on the website), in order to protect the users personal data (like real name).</p>
  
  <p><strong>The Users Collection</strong></p>
  
  <p>Given a data structure like the following it is possible to store a username along with other data for each user:</p>
  
  <pre><code>/users  (collection)
      /{uid}  (document)
          - name: "&lt;the username&gt;"
          - foo: "&lt;other data&gt;"
  </code></pre>
  
  <p>However, nothing prevents another user (with a different <code>{uid}</code>) to store the same <code>name</code> in their record. As far as I know, there is no "security rule" that allows us to check if the <code>name</code> has already been by another user.</p>
  
  <p>Note: A client side check is possible, but unsafe as a malicious client could omit the check.</p>
  
  <p><strong>The Reverse Mapping</strong></p>
  
  <p>Popular solutions are creating a collection with a reverse mapping:</p>
  
  <pre><code>/usernames  (collection)
      /{name}  (document)
         - uid: "&lt;the auth {uid} field&gt;"
  </code></pre>
  
  <p>Given this reverse mapping, it is possible to write a security rule to enforce that a username is not already taken:</p>
  
  <pre><code>match /users/{userId} {
    allow read: if true;
    allow create, update: if
        request.auth.uid == userId &amp;&amp;
        request.resource.data.name is string &amp;&amp;
        request.resource.data.name.size() &gt;= 3 &amp;&amp;
        get(/PATH/usernames/$(request.resource.data.name)).data.uid == userId;
  }
  </code></pre>
  
  <p>and to force a user to create a usernames document first:</p>
  
  <pre><code>match /usernames/{name} {
    allow read: if true;
    allow create: if
        request.resource.data.size() == 1 &amp;&amp;
        request.resource.data.uid is string &amp;&amp;
        request.resource.data.uid == request.auth.uid;
  }
  </code></pre>
  
  <p>I believe the solution is half-way there. However, there are still a few unsolved issues.</p>
  
  <p><strong>Remaining Issues / Questions</strong></p>
  
  <p>This implementation is quite involved already but it doesn't even solve the problem of users that want to <em>change their user name</em> (requires record deletion or update rules, etc.)</p>
  
  <p>Another issue is, nothing prevents a user from adding multiple records in the <code>usernames</code> collection, effectively snatching all good usernames to sabotage the system.</p>
  
  <p>So to the questions:</p>
  
  <ul>
  <li>Is there a simpler solution to enforce unique usernames?</li>
  <li>How can spamming the <code>usernames</code> collection be prevented?</li>
  <li>How can the username checks be made case-insensitive?</li>
  </ul>
  
  <p>I tried also enforcing existence of the <code>users</code>, with another <code>exists()</code> rule for the /usernames collection and then committing a batch write operation, however, this doesn't seem to work ("<em>Missing or insufficient permissions</em>" error).</p>
  
  <p>Another note: I have seen solutions with client-side checks. <em>BUT THESE ARE UNSAFE</em>. Any malicious client can modify the code, and omit checks.</p>