Step-by-Step: User Authentication/Login and Register API Using NestJS (NodeJS), MongoDB, and…
NOTE: Focus on the code, not my grammar 😅💻 — the compiler doesn’t care, and neither should you!
Step-by-Step: User Authentication/Login and Register API Using NestJS (NodeJS), MongoDB, and Swagger ,JWT
NOTE: Focus on the code, not my grammar 😅💻 — the compiler doesn’t care, and neither should you!
- Install Node.js (with nvm for version management) Visit this link for detailed information:
[embed]Install nvm & Node.js Install nvmmedium.com
Install the NestJS Framework Visit this link for detailed information
[embed]Install Node Backend with Nest JS Getting Started with Node.js & NestJSmedium.com
Let’s start User Authentication API Using NestJS (NodeJS), MongoDB, and Swagger
3.1 Setup Mongodb Database 3.1 Create Mongodb Cluster: Visit this link for detailed information to make cloud cluster and get cluster url
[embed]Step-by-Step Guide to Setting Up MongoDB (Cloud) for Your Project Go to MongoDB Atlasmedium.com
3.2 Install dependencies
npm install @nestjs/mongoose mongoose
npm install @nestjs/config
3.3 Define Cluster Variable in ENV
Go to .env file and define the cluster variable
MONGO_URI=mongodb+srv://username:some-id-autogenerated.mongodb.net/
3.4 Configure MongoDB in AppModule
In src/app.module.ts: 3.4.1:
import { MongooseModule } from '@nestjs/mongoose'
import { ConfigModule } from '@nestjs/config';
3.4.2 Under Module Imports array add the db connection as an array item as given below:
@Module({imports: [
ConfigModule.forRoot({ isGlobal: true }),
MongooseModule.forRoot(process.env.MONGO_URI),
]
Database connection is almost done as per the above instructions, now let's start with the user auth api feature
4. Install required packages:
npm install class-validator class-transformer
npm install @nestjs/passport passport passport-local
npm install @nestjs/jwt passport-jwt
npm install bcrypt
npm install - save-dev @types/bcrypt
npm i @nestjs/swagger
Note use --force after package name, if any dependancy issue
4.1 Setup Swagger
Go to src/main.cs
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// ✅ Enable Validation Globally (if not already)
app.useGlobalPipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
forbidUnknownValues: true,
}));
// ✅ Define the swagger
const config = new DocumentBuilder()
.setTitle('User Auth API')
.setDescription('NestJS Auth Example with MongoDB')
.setVersion('1.0')
.addTag('Auth')
.build();
const documentFactory = () => SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, documentFactory);
await app.listen(3000);
}
bootstrap();
Open http://localhost:3000/api to test Swagger.
- Create DTO file for validate fields 5.1 : src/users/dto/create-user.dto.ts
import { IsEmail, IsNotEmpty, IsOptional, IsString, IsDateString, IsEnum,
MinLength, IsNumberString,} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty()
@IsNotEmpty({ message: 'First name is required' })
@MinLength(1)
@IsString()
firstName: string;
@ApiProperty()
@IsNotEmpty({ message: 'Last name is required' })
@MinLength(1)
@IsString()
lastName: string;
@ApiProperty()
@IsNotEmpty({ message: 'Email is required' })
@IsEmail({}, { message: 'Invalid email format' })
email: string;
@ApiProperty()
@IsNotEmpty({ message: 'Phone is required' })
@IsNumberString({}, { message: 'Phone must contain only numeric digits' }) // ✅ validate numeric only
phone: string;
}
5.2 src/users/dto/login.dto.ts
import { IsEmail, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class LoginDto {
@ApiProperty()
@IsEmail()
email: string;
@ApiProperty()
@IsNotEmpty()
password: string;
}
5.3 Create user schema : src/users/schemas/user.schema.ts
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { Types } from 'mongoose';
export type UserDocument = User & Document;
@Schema({ timestamps: true }) // Automatically adds createdAt and updatedAt
export class User {
/* @Prop({ type: Types.ObjectId })
_id: Types.ObjectId; */ // Comment this if using mongodb
@Prop({ required: true })
firstName: string;
@Prop({ required: true })
lastName: string;
@Prop({ required: true, unique: true, lowercase: true, trim: true })
email: string;
@Prop({ required: true, unique: true })
phone: string;
}
export const UserSchema = SchemaFactory.createForClass(User);
6. Creating an authentication module, but before creating the authentication module, the service and controller. First, we will create the User module and the Service
$ nest g module users $ nest g service users
(nest g module users command create new module for user under src/users/users.module.js to define schema Also, auto updated the src/app.module.ts to assign module to Module function as we did for Manual for MongooseModule in the previous step [3.4.2].)
6.1 src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { User, UserSchema } from './schemas/user.schema'; // Import schema
import { MongooseModule } from '@nestjs/mongoose'; // Import MongooseModule
@Module({
imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])], // Define schema
providers: [UsersService],
exports: [UsersService], // ✅ Add Service for export
})
export class UsersModule { }
6.2 Go to src/users/users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User, UserDocument } from './schemas/user.schema';
import * as bcrypt from 'bcrypt';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UsersService {
// ✅ Define constructor
constructor(@InjectModel(User.name) private userModel: Model<UserDocument>) { }
// ✅ Define find user function from database
async findByEmail(email: string): Promise<User | undefined> {
return this.userModel.findOne({ email });
}
// ✅ Define create user function to store register data in to the database
async create(dto: CreateUserDto): Promise<User> {
const passwordHash = await bcrypt.hash(dto.password, 10);
const createdUser = new this.userModel({
...dto,
passwordHash,
});
return createdUser.save();
}
}
- We’ll start by generating an
AuthModuleand in it, anAuthServiceand anAuthController. We'll use theAuthServiceto implement the authentication logic, and theAuthControllerto expose the authentication endpoints.
$ nest g module auth
$ nest g controller auth
$ nest g service auth
7.1 : Let's create JWT_SECRET_KEY for the auth token handling. Run this in your terminal:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Output :
4a1d8f1a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234
Go to .env file:
JWT_SECRET_KEY=4a1d8f1a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234
7.2: Go to src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
// import { JwtStrategy } from './jwt.strategy'; // Define later
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
UsersModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
secret: configService.get<string>('JWT_SECRET_KEY'), // ✅ ENV key
signOptions: { expiresIn: '1d' },
}),
}),
],
controllers: [AuthController],
providers: [AuthService]
})
export class AuthModule {}
7.3 Go to src/auth/auth.service.ts
import { Injectable, UnauthorizedException, BadRequestException } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import { CreateUserDto } from '../users/dto/create-user.dto';
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) { }
async register(dto: CreateUserDto) {
const existing = await this.usersService.findByEmail(dto.email);
if (existing) {
throw new BadRequestException('User already exists');
}
const user = await this.usersService.create(dto);
return {
message: 'Registration successful',
};
}
private generateToken(user: any) {
const payload = { sub: user._id, email: user.email };
return this.jwtService.sign(payload);
}
async validateUser(email: string, password: string): Promise<any> {
const user = await this.usersService.findByEmail(email);
if (user && await bcrypt.compare(password, user.password)) {
return user;
}
return null;
}
async login(email: string, password: string) {
const user = await this.usersService.findByEmail(email);
if (!user) {
throw new UnauthorizedException('Invalid email');
}
const isMatch = await bcrypt.compare(password, user.passwordHash);
if (!isMatch) {
throw new UnauthorizedException('Invalid password');
}
return {
message: 'Login successful',
accessToken: this.generateToken(user),
};
}
}
7.4 Go to src/auth/auth.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { CreateUserDto } from '../users/dto/create-user.dto';
import { LoginDto } from '../users/dto/login.dto';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) { }
@Post('register')
register(@Body() dto: CreateUserDto) {
return this.authService.register(dto);
}
@Post('login')
login(@Body() dto: LoginDto) {
return this.authService.login(dto.email, dto.password);
}
}
7.5 Cross-check to make sure to imported the 'AuthModule' in app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config';
import { UsersModule } from './users/users.module';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
MongooseModule.forRoot(process.env.MONGO_URI),
UsersModule,
AuthModule,// ✅ Make sure its added
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule { }
✅ Done!
Now you can:
- Visit
[**http://localhost:3000/api](http://localhost:3000/api)** - Test your endpoints directly via Swagger UI
- View DTOs, request bodies, and responses
- Authorize using JWT token with the
Authorize 🔒button
If this code saved you time or effort, you can support me with a coffee :
[MY GPAY UPI ID: soruwww@okicici ]
[My Paypal : https://www.paypal.com/paypalme/SourabhWadhwa ]
💬 Have any questions or run into issues? Drop a comment — I’m happy to help you out!
메타데이터
- post_id
- 31e4c86e46b3
- slug
- step-by-step-user-authentication-login-and-register-api-using-nestjs-nodejs-mongodb-and-31e4c86e46b3
- url
- https://medium.com/@soruwww/step-by-step-user-authentication-login-and-register-api-using-nestjs-nodejs-mongodb-and-31e4c86e46b3
- canonical_url
- https://medium.com/@soruwww/step-by-step-user-authentication-login-and-register-api-using-nestjs-nodejs-mongodb-and-31e4c86e46b3
- author_url
- https://medium.com/@soruwww
- status
- ok
- fetched_at
- 2026-06-15 22:55:51