
Designing unique game id's and join codes
This solution was part of the Séance app I created. For Séance, I used the Supabase BaaS platform to provide database and realtime features, backed by Postgres. All you need to know about Séance for this post is that, in Séance, users can either create a new game, or join an existing one using a game identifier given to them by another user.
In the early stages of the app, the player would join a game by entering the game’s primary key id from the database. This worked, but it isn’t really what a primary key is for, and the sequential nature meant a troll could discover id’s that were likely to be in use and disrupt somebody’s game.
The clearest solution for the sequentialness problem was to change the type of the id column to a uuid
, provided by the
uuid-ossp extension that Supabase makes easily available. I used the function uuid_generate_v4
(also
provided by uuid-ossp) to generate non-sequential random values that look like:
a8c7fbce-5e0c-4691-96e6-0bc75164e67d
Obviously, these uuid’s are difficult for a user to enter to join a game (and I was trying to get away from using primary keys for that anyway), so I added a join_code
column.
To get user-friendly, non-sequential, close-enough-to-random join codes took a few steps:
- I created a Postgres sequence called
seance_id_sequence
(not the best name in hindsight). I used all defaults, but set it to cycle in case it ever runs out (it won’t on this app though). - I enabled the pg_hashids extension to make its
id_encode
function available. - I made a function called
generate_join_code
, defined as:
begin
new.join_code := id_encode(nextval('seance_id_sequence'), 'salt', 6, '0123456789abcdef');
return new;
end
This will create a (usually) 6-character code, seeded with the next number in the sequence, using only numbers and lowercase letters ‘a’ through ‘f’.
- I made a trigger to assign the value of
generate_join_code()
toseance.join_code
whenever a new séance is created, on theBEFORE INSERT
event.
With that, all the above problems were solved. Séance id’s are no longer guessable, are no longer used to join games, and are no longer presented to users in the UI. Instead, players can join games with join codes, which are concise, human-friendly, and unguessable.