How I force private games in Colyseus with Auth0 and manage rooms for long played games
3 min read
How I force private games in Colyseus with Auth0 and manage rooms for long played games Hi, what's up? I decided to write about the way I handle my games and game rooms in my Colyseus-based game server.
My game is an online persistent-universe single/co-op player game where your games continue even when you are logged out of your account. In this 4X/resource-management space-themed game, resources are extracted, things are built, researched advances, even when you're offline.
Early on, I made a decision that I don't want a Colyseus game room open for each game and having long-running rooms forever, but rather that for every game session I'll open a dedicated room. When a player or a group of players logs in and chooses the game, a game room is created for them and the room state is synced with the actual game data in the database. The room state is also synced when the game "ticks" or other events occur and all connected clients are updated automatically by Colyseus.
The way I made things work is as such. I have a regular endpoint in my API, separated of Colyseus, that the client calls to get a reservation for a room. Using the Colyseus MatchMaker API I first query for room with a certain identifier for the game, I call it the gameName, at least for now. If that does not exist then I create such room with the name identifier and matchMaker.reserveSeatFor it. If I do find such game then I create a reservation using .matchMaker.joinById as I now know the ID of the room. In both cases, I get a reservation object that I send to the client which consumes it with the Colyseus client API. And the client joins the game.
This is nice, but there's a small catch to how I do things.
I use Auth0 for authentication. It's easy enough to protect my own API endpoints with Auth0, but I did not find a way to protect the Colyseus routes with that same authentication middleware. That made me very sad. I went to sleep on it and in the morning I realized that I can do a funny workaround. My endpoint for requesting a reservation do gets the auth JWT as it's one of the regular protected endpoints. It turns out I can attach options to the reservation object, so I just attached the JWT itself to the reservation.
When the client consumes the reservation, the options from the reservation somehow arrives to the onAuth handler on the GameRoom class as the client is not supposed to tamper with the reservation object. In any case it does tamper for some hacky reason, I fire up my JWT validation again and can deny or approve the user.
It works. One thing that I worry about is multiple coop players, where each is going to use their own JWT and I'm not sure if the reservations will work properly and nothing will go nuts. I'll test that sometime but I think I'm fine.