for (let i = startOfSoftwareDevelopingLife; i < endOfSoftwareDevelopingLife; i++){
DO ("AUTHENTICATION!")
}
NPM Library - https://www.npmjs.com/package/dewmyth-auth-nestjs-mongo
GitHub Repository - https://github.com/dewMyth/dewmyth-auth-nestjs-mongo
AUTHENTICATION, one of most important (yet boring 😒) process when building a software application. However you can't avoid that even though it is the same thing again and again. So my try here is to make your life easier for you when you need an authentication flow. Just use two function calls to register a user and login a user. 😎
Note: If you are very new to software development and authentication concepts, Please do and practice the authentication, implement those by scratch. Don't use these kinds of libraries.
What does this library do?
This is a NestJS based library that uses Mongo DB as the database to save the user and authenticate user by generating a JWT token.
If you are not familiar with NestJS, think it as the JavaScript framework that similar to what Spring for Java or what .NET for C#. (Pros, don't throw rocks at me 🥸). If you are a NodeJS developer that never excavated NestJS, give it a try. They have one of the best documentations (https://nestjs.com/) I have ever seen in my tiny developing life 👶.
Who need this library?
For those who want to focus more on your business logic of the application rather than allocating time for an authentication process.
Functionality
Once you have generated a MongoDB database connection URI and provided it to the library, you will have access to the register user and login user functions.
Register User
For this createUser
function, you have to do only passing the email, password (username as well, but it is optional). It will generate a user object as below with a hashed password. (with 10 salt rounds)
Login User
In loginUser
function, you have to pass the email and password to get an JWT authentication token. Optionally you can pass the JWT Secret key and token TTL (time to live) as well.
More on How to use the library - https://github.com/dewMyth/dewmyth-auth-nestjs-mongo/blob/master/README.md
How I implemented this library
OK!!! Now that the shortcut gang, those who just want to use the library without breaking a sweat have left the building, it’s just us 🤣. Let's dive into how to implement this NPM library from scratch. So you can build your own. 😎
Step 1 - Create a NestJS Application. - https://docs.nestjs.com/
This will create a boilerplate NestJS application.
Step 2 - Install mongoose
and @nestjs/mongoose
-https://docs.nestjs.com/techniques/mongodb
npm i @nestjs/mongoose mongoose
This will be used to create the MongoDB schema for the users database/collection.
Step 3 - Create the auth
module.
Use the following command to create a new module called auth
nest g res auth
Use REST API and then press "n" to avoid creating sample CRUD endpoints.
Then make sure to import the AuthModule
to the AppModule
imports if it is not added to there already.
Step 4 - Create the UserSchema with the User data you need. Make sure to have a unique field to identify a user (such as email or username) and password.
File location - src/auth/schemas/user-schema.ts
HAHA! I am not going to make it textual. DO IT FOR YOURSELF. Write the code. Don't Copy N Paste.
Step 5 - Create DTO types.
File location - src/auth/dto/create-user.dto.ts
, src/auth/dto/login-user.dto.ts
We will need TWO DTO types for this. One to createUserDTO
and to LoginUserDTO
.
Why we need DTO ? Since we are making a library, it is very important to make the life easier for the library user. So here if we use the DTOs for the input, when the exposed functions are used by the user it will show the relevant parameters as suggestions.
Sample Usage when using the library:
Step 6 - Like wise I have created a response type for the logged user as well.
File location - src/auth/types/login-user.response.ts
Like the suggestions for input parameters above, we will have the Promise type for the logged in user's data when we use this login user response type.
Sample Usage when using the library:
Step 7 - Inject the UserSchema / Model to your AuthService
Step 8 - Install bcrypt
library and import the library to AuthService
- https://www.npmjs.com/package/bcrypt
npm install bcrypt
This library will be used to hash the password.
Step 9 - Implement the createUser
function.
Pass the user entered data to the createUser function. It should be under the type CreateUserDTO
and should also map with the UserSchema
created above.
Then extract the email and password from the payload.
Email for the checking an existing user with the same email :
Do a simple Mongoose findOne()
using the email and if there is a user already. Throw the shown error. This will stop the function's further processing and will throw the error to the user.
Password for the hashing process :
Use bcrypt
library's .hash()
function to make the password. I have use 10 round of salts for the hashing.
If you want to give a customize number to user to control the salt rounds, pass another argument to this createUser
function and hash using that. More power to the user 💪.
Then attached the hashed password to the final payload and do save in the MongoDB using the Mongoose .save()
function.
I have also returned the saved user as the final output of the createUser
function's happy path.
Step 10 - Install jsonwebtoken
library and import the library to AuthService
- https://www.npmjs.com/package/jsonwebtoken
npm i jsonwebtoken
Step 11 - Implement the loginUser
functionality
Pass the user entered data, it should be in the type of LoginUserDTO
. Apart from that I have also used 2 optional arguments. secret
- to pass the JWTSecret key and tokenTTL
- to assign a TTL for the JWT token.
Extract the email and the password.
Use email and mongoose findOne()
to check there a user with an existing email. If not throw an error to the user.
If there is user with that email, Then need to check the password hash is match for the saved salt for that email's user. For that we can use bcrypt
library's .compare()
function with the DB fetched user's hash and the password that the user has entered under the loginCredentials
. If it's not a match, throw an error message to the User.
If it is a match, procced with creating the JWT token for that user by using the jsonwebtoken
's sign
function. Pass the data that you want to encrypt inside the token. In this case I have attached the user's email. (So once the user is logged in to the service, we can decode and get the user's email). If there are no parameters to the optional arguments. By default secret will be secret
and the tokenTTL will be 1h (one hour).
Now the the business logics of the NestJS/MongoDB Authentication is done.
Step 12 - Make AuthModule
a Dynamic Module. -- IMPORTANT
When you need to use a general NestJS module for different use case scenario's you need to make that NestJS module a dynamic module. -https://docs.nestjs.com/fundamentals/dynamic-modules
Here, our AuthModule
should accept a Mongo Connection, when it is used by different different users that Mongo Connection should be variable. So we have to make this AuthModule
a reusable dynamic module and pass an argument to accept the Mongo Connection URI.
Now your Dynamic AuthModule
should be like this. Replace the existing AuthModule
with the following.
import { DynamicModule, Global, Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { MongooseModule } from '@nestjs/mongoose';
import { UserSchema } from './schemas/user.schema';
import { AuthModuleOptions } from './auth-module-options';
@Global()
@Module({})
export class AuthModule {
static forRoot(options: AuthModuleOptions): DynamicModule {
return {
module: AuthModule,
imports: [
MongooseModule.forRoot(options.mongoUri),
MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
],
controllers: [AuthController],
providers: [AuthService],
exports: [AuthService],
};
}
}
Inside the import
array of the dynamic AuthModule
. Mongoose Connection URI should be coming from the options.
Create another type file that accept a string as the mongo uri. That should be the type that dynamic AuthModule
should accept as parameters.
Apart from the imports, as usual keep the test controllers and the exposed services as providers and exports.
Step 13 - Build and Publish the NPM library
Now we need to export out our dynamic AuthModule
and the AuthService
where the business logic contains.
Create a file called index.ts
in the src
directory. And export all the content of that above mentioned files as below.
Now, change the main:
key in the package.json
as below.
dist
is the directory where the build files of the NestJS application will be kept. (If you didn't changed in the tsconfig.json
's outDir
key).
Now do build the created library. 😎
npm run build
If you see something like this in the dist/index.js
file. You are good to go. (Exported files should be there as code.)
Now, do a
npm login
And login to the https://www.npmjs.com/ and create an account.
Then you will be able to the publish your library.
The name of your library will be as per the name
key of package.json
. So make sure to have unique package name before publishing.
DO PUBLISH!!!
npm publish
Boom!!!. You are done.
Congratulations Neo!
⠀⠀⠀⠀⠀⠀⢀⣤⣶⣶⣶⣶⣦⣤⣀⠀⠀⠀⠀⠀
⠀⠀⢀⣤⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀
⠀⢠⣿⣿⣿⣿⣿⠿⣿⣿⣿⣿⠿⠿⢿⣿⣿⣷⡀⠀
⠀⢸⣿⡿⠋⠁⠀⠀⠀⠉⠉⠀⠀⠀⠀⠈⢹⣿⡇⠀
⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀
⠀⢸⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀
⠀⢸⣿⣠⣤⣶⣶⣶⣦⣀⣀⣴⣶⣶⣶⣤⣄⣿⡇⡀
⣿⣿⣿⠻⣿⣿⣿⣿⣿⠟⠻⣿⣿⣿⣿⣿⠟⣿⣿⣿
⣿⣿⣿⠀⠈⠉⠛⠋⠉⠀⠀⠉⠙⠛⠉⠁⠀⣿⣿⣿
⠙⢿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡿⠃
⠀⠸⣿⣧⠀⠀⠀⢀⣀⣀⣀⣀⡀⠀⠀⠀⣼⣿⠇⠀
⠀⠀⠙⢿⣷⣄⠀⠈⠉⠉⠉⠉⠁⠀⣠⣾⡿⠃⠀⠀
⠀⠀⠀⢸⣿⣿⣷⣤⣀⣀⣀⣀⣤⣾⣿⣿⡅⠀⠀⠀
⠀⠀⢰⣿⣿⣿⣿⣿⣿⡿⠿⢿⣿⣿⣿⣿⣿⡄⠀⠀
⠀⠀⠻⠿⠿⠿⠿⠿⠿⠷⠴⠿⠿⠿⠿⠿⠿⠇⠀⠀
You have break the Do Authentication cycle. (in a way)
Now you can use this library on your next NestJS project. More on how to use this library - https://github.com/dewMyth/dewmyth-auth-nestjs-mongo/blob/master/README.md
Conclusion
Of course, This is not a perfect library. Many more optimization and features can be added. For an example having dynamic fields for User model, enhance the security of the login functionality, Authorization processes and etc. So feel free to fork and make the PRs if you are interested.
Thanks for reading my long long long article.
If you have any concerns or any criticism please free to drop a comment or contact me through the LinkedIn (www.linkedin.com/in/dewmith-akalanka).
Happy Coding!!!.
Top comments (0)