
I recently had to implement a two factor authentication on a project for my company and it was a whole new thing for me. Sure I had already used 2fa before but I had never implemented it.
What is 2fa ? Well we all know that passwords aren't really secure enough to avoid security breaches so...
2FA is an extra layer of security used to make sure that people trying to gain access to an online account are who they say they are. First, a user will enter their username and a password. Then, instead of immediately gaining access, they will be required to provide another piece of information.
In this case, I was asked to use the google authenticator app to generate a 2fa code that would be used to authenticate the user after the login step.
Here's the login flow for 2fa authentication:
First we have to create a unique secret for every user that turns on 2fa, but we'll also need a special otp authentication url that we'll be using later to create a QrCode. The otplib package is a good match, so let's install it.
yarn add otplib
We should also update the user entity.
typescriptexport class User {@Exclude()@Column({ type: DataType.STRING })twoFactorAuthenticationSecret: string;@Exclude()@Column({ type: DataType.STRING })twoFactorAuthenticationBackupCode: string;}
Then we create a method to generate the secret, backupCode and otpAuthUrl in the authentication service and return them. The TWO_FA_APP_NAME is the name that will appear in the google authenticator app.
typescriptasync generateTwoFactorAuthenticationSecret(user: UserEntity) {const secret = authenticator.generateSecret();const backupCode = StringUtils.random();const otpAuthUrl = authenticator.keyuri(user.email,configParams.TWO_FA_APP_NAME,secret,);await this.userService.set2FASecretAndBackupCode(secret,backupCode,+user.id,);return {secret,backupCode,otpAuthUrl,};}
We have to update the user with the secret and backupCode that has just been generated. Once again, this should all be in a database.
typescriptasync set2FASecretAndBackupCode(secret: string,backupCode: string,userId: number,) {const user = await this.userRepository.findOne({ where: { id: userId } });if (!user) {customThrowError('User not found', HttpStatus.BAD_REQUEST);}await this.userRepository.update({twoFactorAuthenticationSecret: secret,twoFactorAuthenticationBackupCode: backupCode,},{ where: { id: userId } },);}
Now, we can generate the QrCode that will be used to add our application to the google authenticator app.
yarn add qrcode
Let's add the generate method in the authentication service.
typescriptimport { toDataURL } from 'qrcode';async generateQrCodeDataURL(otpAuthUrl: string) {return toDataURL(otpAuthUrl);}
Now we need to offer the possiblity for the user to turn on the 2fa. So let's add another property to the user interface.
typescriptexport class User {@Column({ type: DataType.BOOLEAN, defaultValue: false })is2FAEnabled: boolean;}
Add the switch method in the users service
typescriptasync switchTwoFactorAuthentication(userId: number, status: boolean) {const user = await this.userRepository.findOne({ where: { id: userId } });if (!user) {customThrowError('User not found', HttpStatus.BAD_REQUEST);}await this.userRepository.update({ is2FAEnabled: status },{ where: { id: userId } },);}
Add the method that will verify the authentication code with the user's secret
typescriptasync authenticateWithTwoFactor(code: string, user: UserEntity) {const isCodeValid = await this.isTwoFactorAuthenticationCodeValid(code,user,);if (!isCodeValid) {customThrowError('Wrong authentication code', 401);}const accessToken = await this.authService.createSignInToken({id: user.id,email: user.email,isSecondFactorAuthenticated: user.is2FAEnabled,});return { accessToken, user };}
So first we'll do a POST request to log in with the user and password:

This will return the following:

Then, we need to get the QrCode to add our app to the google authenticator app

This will return a base64 data url which in turn will happen to be a QrCode

If you scan this with the Google Authenticator App it should add your app:

And then you should be able to call the authenticate route with the current code from the google authenticator app

This article provides a detailed overview of the deployment process, infrastructure. It covers everything from Git branching strategies to AWS infrastructure, CI/CD pipelines, database setup, and security considerations.
Beiryu
Contributor

Xin chào các bạn, hôm nay mình sẽ chia sẻ với các bạn về Snowflake - một nền tảng dữ liệu đám mây mà mình đã có cơ hội làm việc và triển khai trong các dự án gần đây. Mình sẽ giải thích về Snowflake, lý do tại sao nó lại quan trọng trong môi trường production, và chia sẻ một số kinh nghiệm thực tế khi làm việc với Snowflake và AWS.
Beiryu
Contributor