How I created the online game “backgammon” (part three). Server

Hi all!

In the previous article I described the server architecture and told how the application itself, which serves the game clients, is arranged. At the end of the article there was a vote on which application modules would be interesting to read about and the votes were mainly divided between the “authorization” and “game” modules.

I decided to start with the authorization module, since it is, in my opinion, the basic one for any project. In the first article, I touched on this topic a little, and this time I want to lay everything out on the shelves.

The first thing that the user interacts with the system is receiving an access key for subsequent authorization. For me, this is a key in the format JSON Web Token (JWT). The key contains a set of data that allows identifying the user on the server side. This is an accessToken, which, as the name suggests, is used to access private methods of various system modules that require authorized access, for example, without this key it is impossible to create a new game or request profile data. In the classic implementation of program interfaces (API) between the client and the server, clients send such a key along with each request to the server in the Authorization header. This header often uses the prefix “Bearer” with a space before the key itself, but this is not really that important, it's just that the term “Bearer authorization” essentially means “Bearer Permission” and many use it to say that authorization works on this principle. Some developers use their prefixes instead of “Bearer”, for example “X-API” or something else, but this does not change the essence, after that there is always a key and it does not matter whether it is JWT or some other version of the key. By the way, on the server side I use a library that I like Jose. This library provides access to a whole range of technologies for creating and verifying keys, in its arsenal are JSON Web Tokens (JWT), JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), JSON Web Key Set (JWKS) and others. In addition, its beauty is that it can work both on the server side and on the client, and it also supports work in different environments for running JavaScript code, such as Node.js, Deno, Bunas well as cloud functions such as Cloudflare Workers and others.

In this project, I have implemented two options for obtaining an access key. The first involves using a digital code sent to the email specified by the user during authentication, and the second is a special method for automatic client authentication in the event of launching an application on the Telegram platform.

Below is a diagram of how the first option works.

scheme of the authorization module operation using codes sent to the mail

scheme of the authorization module operation using codes sent to the mail

During startup, the client application sends a request to update keys to the auth module via HTTP transport, calling the refresh method (in the diagram, Case 1). The request body contains the device identifier (deviceId), the so-called fingerprint, which is pre-generated on the client side. In fact, this is just a hash obtained from a certain set of data that the browser provides about itself and the system where it is running. In addition, this request automatically transmits a Cookie refreshToken in the header, if one was set by the server in the previous session of the application. On the server side, the refresh method checks the received information and searches for a pair of this key and device identifier in the database. Depending on the project load, you should choose the most suitable storage option – this can be PostgreSQL, Redis or something else depending on the stack used and preferences. If the pair is not found in the storage, or the key has expired, the method returns an error with the corresponding code in the response. If a link with a non-expired lifetime is detected, the method sends the generated accessToken to the client and sets the value of the new refreshToken via the Set-Cookie header, which will be transmitted to the server each time, during subsequent requests. It is worth noting here that the cookie containing the refreshToken is set with the “http-only” parameter, which does not allow its value to be obtained from the browser programmatically, and this is how secure storage of the refreshToken on the client side is implemented.

If an error occurs when calling the refresh method, the client application displays the user authentication screen, where they are asked to enter an email address to send the code. After entering the address, the application sends a request to the auth module via HTTP transport, calling the getCode method (in the diagram, Case 2). The request body contains the email address and the language used, which is automatically taken from the system settings on the browser side or can be directly specified through the application interface. On the server side, the getCode method checks whether the language parameter is in the list of available languages, and if it is not there, the value is replaced with English. Then the server checks the correctness of the email address and, in case of an error, sends a response to the client with the appropriate code. If the address is correct, the method converts all its characters to lowercase and searches for the address in the database. If this address is missing, a new user is registered in the system. Basic rights are assigned to him, all the necessary parameters are specified, and the received data is returned to the getCode method, where an authorization code consisting of 6 digits is generated and the lifetime of this code is set. At the next stage, the server queues up a letter template with an authorization code and the language parameter for sending, so that the user receives a letter in the specified language, and a response is sent about the successful completion of the operation. On the client application side, a form for entering a confirmation code is displayed, and after receiving the letter, the user enters the code and the application sends an HTTP request to the auth module, calling the withCode method, which passes the same email address, the code from the letter, and the device identifier. The server, in turn, checks the email address, converts the characters to lowercase, searches for a record with this address in the database, and if found, checks the code and its lifetime. If the transferred data is incorrect, or the code does not match the record in the database, or its lifetime has expired, the server sends a response to the client with the corresponding error code. Otherwise, the server generates keys and sends the same response as at the end of the first scenario (Case 1).

As I wrote above, in addition to the authentication option using a code sent to the mail, another method was implemented within the framework of this project, specifically for the platform Telegram Mini AppsThe operation diagram of this option is presented below.

scheme of the authorization module operation using data received from the Telegram platform

scheme of the authorization module operation using data received from the Telegram platform

Relatively recently, Telegram announced about the launch of their mini-app platform, which gives the opportunity to gain access to a huge number of Telegram users by publishing an application in the store. They also introduced a new type of mini-app, which is incredibly easy to integrate into their platform.

The Telegram mini app is essentially a web app running in the WebView of the Telegram app itself, which is also essentially a browser. Thanks to this mechanism and scriptwhich must be placed in the HTML code of the application, the developer gets access to the Telegram user data (and much more), which is placed in the global window.Telegram.WebApp object. However, this data can be compromised on the way to the server and therefore it is necessary to implement their verification. For these purposes, the withTelegramAccount method is implemented on the server side, which is also located in the authorization module (auth).

During the startup process, the client application checks for the presence of this data in the global scope and, if it is found, sends it to the server using HTTP. The server, on its part, checks this data using a special signature system using the key from the bot that is the owner of the application.

After checking the signature and making sure that the received information is correct, the server checks for the presence of a user with the Telegram user ID in the database; if the user is not found, then the standard registration procedure takes place and then, as in the case of finding such a user in the database, the application generates keys (accessToken and refreshToken) and sends them in response to the client, and if any errors are detected, a message with the corresponding error code is sent.

This mechanism allows for very quick integration of Telegram user authentication using existing authorization module methods. In the future, a similar mechanism will be used to implement user authentication using the OAuth2.0 protocol for users with a Google or Apple account.

This concludes the description of the authorization module and I suggest asking questions not only to me in Telegram, but also in the comments to the article. There are probably some points that are worth describing in more detail. For example, I have consciously stopped using passwords to access my account for several years now and use only one-time codes and OAuth providers. This allows me to avoid password theft due to their absence and thus significantly increase security. In some of my projects, I also used a two-factor authentication system (2FA), when after entering a password or code, you need to use a code generator to gain access, but in this case, you need to perform many more actions and the implementation of such a system seems redundant to me in this project.

There will be no voting this time, because the next topic of the article is the “game” server module.

P.S. The game now has the ability to change the avatar and board image, and also has an interface for creating your own boards with a variety of designs, which is currently only available to users with “designer” rights. You can play backgammon with friends or test yourself in a battle with AI as always at link.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *