NestJS: Building the Base

NestJS: Building the Base

NestJS is a framework used to build the server-side of an application. Here I’m going to explain how to build the base of the application with basic security features.

Start New Project

First, you need to install NestJS CLI with the following command. You might require root permission for this command.

 npm i -g @nestjs/cli

Then use the following command to create a new project.

nest new project_name
cd project_name

Hot Reload

The next step would be adding auto building (Hot Reload) to the project so you don’t need to build the project in every code modification. For that, you need to install the following dev dependencies.

npm i --save-dev webpack-node-externals run-script-webpack-plugin webpack

Then create a new file named webpack-hmr.config.js in your root directory. Insert the following code in it.

const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename }),
    ],
  };
};

Then open the main.ts file in the src and replace its code with the following.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

Now open the package.json in your root directory and replace start:dev script with the following.

"start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js --watch"

Now start the application using the following command.

npm run start:dev

Basic Login Authentication

Now I’m going to explain how to add the basic login authentication to the app you have just created. You need the following dependencies and dev dependencies for this.

npm install --save @nestjs/passport passport passport-local
npm install --save-dev @types/passport-local

Then you need to generate the Auth and User modules with services with the following commands.

nest g module auth
nest g service auth
nest g module users
nest g service users

Now let’s generate an interface to represent the user with the following command.

nest g interface interfaces/user

And add the following code.

export interface UserData {
    id: number
    username: string
    password: string
}

Now open the users/users.service.ts file and enter the following code. Here I have created two example users and a function to search for a user.

import { Injectable } from '@nestjs/common';
import { UserData } from 'src/interfaces/user.interface';

@Injectable()
export class UsersService {
    private readonly users: Array<UserData> = [
        {
            id: 1,
            username: "admin",
            password: "1234"
        },
        {
            id: 2,
            username: "user",
            password: "4567"
        }
    ]

    async find(username: string): Promise<UserData | undefined> {
        return this.users.find(user => user.username === username)
    }
}

Then export the UsersService in the users/users.module.ts file so it will be visible to the outside of the module.

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';

@Module({
  providers: [UsersService],
  exports: [UsersService]
})
export class UsersModule {}

Now open the auth/auth.service.ts file and enter the following code. Here a function is created to validate the user with the support of UsersService.

import { Injectable } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';

@Injectable()
export class AuthService {
    constructor(private usersService: UsersService) {}

    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.find(username)

        if(user && user.password === password){
            const { password, ...result } = user
            return result
        }

        return null
    }
}

Then import the UsersService to the Auth Module by editing auth/auth.module.ts file.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [UsersModule],
  providers: [AuthService]
})
export class AuthModule {}

Now create a new file named local.strategy.ts in the auth folder to implement the local authentication strategy. And enter the following code in it.

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super()
    }

    async validate(username: string, password: string): Promise<any> {
        const user = await this.authService.validateUser(username, password)

        if(!user){
            throw new UnauthorizedException()
        }

        return user
    }
}

Then you need to configure auth module to use the local strategy by importing the PassportModule and providing the LocalStategy as follows.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [
    UsersModule, 
    PassportModule
  ],
  providers: [AuthService, LocalStrategy]
})
export class AuthModule {}

Now you should generate a file named local-auth.guard.ts in the auth folder to implement the local guard which is going to be initiated in the login request as follows.

nest g gu auth/guards/local-auth

And enter the following code in it.

import { Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}

Now let’s create a controller in auth with the following command.

nest g co auth

Then create a POST request in it and initiate LocalAuthGuard as follows.

import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { LocalAuthGuard } from './guards/local-auth.guard';

@Controller('auth')
export class AuthController {
    constructor() {}

    @UseGuards(LocalAuthGuard)
    @Post('login')
    async login(@Request() req) {
        return req.user
    }
}

Now the basic login authentication code is finished. Create a POST request to http://localhost:3000/auth/login with JSON body including username and password.

curl -X POST http://localhost:3000/auth/login -d '{"username": "admin", "password": "1234"}' -H "Content-Type: application/json"

You should get user information if the login is successful and if not, it should give you an error message.

Integrating JWT Authentication

Before integrating JWT to the above project, you need to install the following dependencies and dev dependencies.

npm install --save @nestjs/jwt passport-jwt
npm install --save-dev @types/passport-jwt

Then open the auth/auth.service.ts file and create a method to sign the user with the required details as follows.

import { Injectable } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private usersService: UsersService, private jwtService: JwtService) {}

    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.find(username)

        if(user && user.password === password){
            const { password, ...result } = user
            return result
        }

        return null
    }

    async sign(user: any) {
        const payload = { username: user.username, sub: user.id }

        return {
            access_token: this.jwtService.sign(payload)
        }
    }
}

Now you need to create a secret key and expire time to be used in the JWT method. Create a new configuration file in src/config folder named auth.config.ts and enter the key as follows.

export const jwtConfig = {
    secret: "secretKey",
    expireTime: "1h",
    expireIgnore: false
}

Now update the auth.module.ts file as follows.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { jwtConfig } from 'src/config/auth.config';

@Module({
  imports: [
    UsersModule, 
    PassportModule,
    JwtModule.register({
      secret: jwtConfig.secret,
      signOptions: {
        expiresIn: jwtConfig.expireTime
      }
    })
  ],
  providers: [AuthService, LocalStrategy],
  controllers: [AuthController],
  exports: [AuthService]
})
export class AuthModule {}

Now update the auth.controller.ts file as follows.

import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalAuthGuard } from './guards/local-auth.guard';

@Controller('auth')
export class AuthController {
    constructor(private authService: AuthService) {}

    @UseGuards(LocalAuthGuard)
    @Post('login')
    async login(@Request() req) {
        return this.authService.sign(req.user)
    }
}

Now send the previous POST request again and you should get the JWT token as the response.

curl -X POST http://localhost:3000/auth/login -d '{"username": "admin", "password": "1234"}' -H "Content-Type: application/json"

Next, I’m going to initiate JWT token guard for each request.

Now you have to create a file named jwt.strategy.ts in the auth folder and implement the JWT validation strategy in it as follows.

import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy, ExtractJwt } from "passport-jwt";
import { jwtConfig } from "src/config/auth.config";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor() {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: jwtConfig.expireIgnore,
            secretOrKey: jwtConfig.secret
        })
    }

    async validate(payload: any) {
        return { id: payload.sub, username: payload.username}
    }
}

Then add JwtStrategy to the providers list of auth.module.ts file.

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';
import { AuthController } from './auth.controller';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './jwt.strategy';
import { jwtConfig } from 'src/config/auth.config';

@Module({
  imports: [
    UsersModule, 
    PassportModule,
    JwtModule.register({
      secret: jwtConfig.secret,
      signOptions: {
        expiresIn: jwtConfig.expireTime
      }
    })
  ],
  providers: [AuthService, LocalStrategy, JwtStrategy],
  controllers: [AuthController],
  exports: [AuthService]
})
export class AuthModule {}

Now generate jwt-auth.guard.ts file in the auth folder as follows.

nest g gu auth/guards/jwt-auth

And implement the JWT guard which is going to be initiate in each request as follows.

import { Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

Now let’s create a controller for users and implement protected routes in it using JWT guard. First, create the controller as follows.

nest g co users

Then update the users.service.ts file as follows.

import { Injectable } from '@nestjs/common';
import { UserData } from 'src/interfaces/user.interface';

@Injectable()
export class UsersService {
    private readonly users: Array<UserData> = [
        {
            id: 1,
            username: "admin",
            password: "1234"
        },
        {
            id: 2,
            username: "user",
            password: "1234"
        }
    ]

    async find(username: string): Promise<UserData | undefined> {
        return this.users.find(user => user.username === username)
    }

    async findByID(id: number): Promise<UserData | undefined> {
        return this.users.find(user => user.id == id)
    }

    async findAll(): Promise<Array<UserData>> {
        return this.users;
    }
}

Then create some protected API calls in the users.controller.ts file as follows.

import { Controller, Get, NotFoundException, Param, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {

    constructor(private userService: UsersService) {}

    @UseGuards(JwtAuthGuard)
    @Get()
    async getAllUsers() {
        const users = await this.userService.findAll()

        let results = []
        users.forEach(user => {
            const { password, ...result } = user
            results.push(result)
        });
        
        return results
    }

    @UseGuards(JwtAuthGuard)
    @Get(':id')
    async getUser(@Param() params) {
        const user = await this.userService.findByID(Number(params.id))

        if(user){
            const { password, ...result } = user
            return result
        }else{
            throw new NotFoundException()
        }
        
    }
}

Now you need to use the token that you got from the login request to send a request as follows.

curl http://localhost:3000/users/1 -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR..."

Integrating Authorization

Here I’m going to explain how to add Permission-based authorization to the project.

First of all, let’s create some permissions. Create a file named permission.enum.ts in src/enums folder and put some permissions as follows.

export enum Permission {
    GET_USER = 'get_user',
    GET_ALL_USERS = 'get_all_users'
}

Now you need to introduce permissions to the user.interface.ts file as follows.

import { Permission } from "src/enums/permission.enum";

export interface UserData {
    id: number
    username: string
    password: string
    permissions: Permission[]
}

Then let’s add some permissions for the two users that we have created before.

import { Injectable } from '@nestjs/common';
import { Permission } from 'src/enums/permission.enum';
import { UserData } from 'src/interfaces/user.interface';

@Injectable()
export class UsersService {
    private readonly users: Array<UserData> = [
        {
            id: 1,
            username: "admin",
            password: "1234",
            permissions: [
                Permission.GET_USER,
                Permission.GET_ALL_USERS
            ]
        },
        {
            id: 2,
            username: "user",
            password: "1234",
            permissions: [
                Permission.GET_USER
            ]
        }
    ]

    async find(username: string): Promise<UserData | undefined> {
        return this.users.find(user => user.username === username)
    }

    async findByID(id: number): Promise<UserData | undefined> {
        return this.users.find(user => user.id == id)
    }

    async findAll(): Promise<Array<UserData>> {
        return this.users;
    }
}

Then you should create a decorator as follows to be used to specify the permissions required to access the resource.

nest g d decorators/permissions

And implement the code as follows.

import { SetMetadata } from '@nestjs/common';
import { Permission } from 'src/enums/permission.enum';

export const PERMISSIONS_KEY = 'permissions'
export const Permissions = (...permissions: Permission[]) => SetMetadata(PERMISSIONS_KEY, permissions)

Now let’s generate a guard for permissions as follows.

nest g gu auth/guards/permissions

In the permissions.guard.ts file, implement the permission comparison method for the user as follows.

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PERMISSIONS_KEY } from 'src/decorators/permissions.decorator';
import { Permission } from 'src/enums/permission.enum';

@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredPermissions = this.reflector.getAllAndOverride<Permission[]>(PERMISSIONS_KEY, [
      context.getHandler(),
      context.getClass()
    ])

    if(!requiredPermissions) {
      return true
    }

    const { user } = context.switchToHttp().getRequest()

    return requiredPermissions.some((permission) => user.permissions?.includes(permission))
  }
}

Now open the jwt.strategy.ts file and add permissions in the return of the validate function, so the PermissionGuard will get permissions to compare.

import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { Strategy, ExtractJwt } from "passport-jwt";
import { jwtConfig } from "src/config/auth.config";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor() {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: jwtConfig.expireIgnore,
            secretOrKey: jwtConfig.secret
        })
    }

    async validate(payload: any) {
        return { id: payload.sub, username: payload.username, permissions: payload.permissions}
    }
}

And then open the auth.service.ts file and enter permissions to the payload so the signed payload will have permissions.

import { Injectable } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
    constructor(private usersService: UsersService, private jwtService: JwtService) {}

    async validateUser(username: string, password: string): Promise<any> {
        const user = await this.usersService.find(username)

        if(user && user.password === password){
            const { password, ...result } = user
            return result
        }

        return null
    }

    async sign(user: any) {
        const payload = { username: user.username, sub: user.id, permissions: user.permissions }

        return {
            access_token: this.jwtService.sign(payload)
        }
    }
}

Now open the users.controllers.ts file and add @Permission(Permission.PERMISSION) decorator to the requests as required.

Since both JwtAuthGuard and PermissionsGuard are used in every request here, move them to the top of the class.

import { Controller, Get, NotFoundException, Param, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard';
import { PermissionsGuard } from 'src/auth/guards/permissions.guard';
import { Permissions } from 'src/decorators/permissions.decorator';
import { Permission } from 'src/enums/permission.enum';
import { UsersService } from './users.service';

@Controller('users')
@UseGuards(JwtAuthGuard, PermissionsGuard)
export class UsersController {

    constructor(private userService: UsersService) {}
    
    @Get()
    @Permissions(Permission.GET_ALL_USERS)
    async getAllUsers() {
        const users = await this.userService.findAll()

        let results = []
        users.forEach(user => {
            const { password, ...result } = user
            results.push(result)
        });
        
        return results
    }

    @Get(':id')
    @Permissions(Permission.GET_USER)
    async getUser(@Param() params) {
        const user = await this.userService.findByID(Number(params.id))

        if(user){
            const { password, ...result } = user
            return result
        }else{
            throw new NotFoundException()
        }
        
    }
}

You can provide these app guards in the module as follows as well.

providers: [
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard
    },
    {
      provide: APP_GUARD,
      useClass: PermissionsGuard
    }
  ],

But here I didn’t do that because the UsersModule is imported to the AuthModule as well. So if I provide them in the module, it will be applied to the Auth Module and the login request will also be checked for the JWT access.

Integrating Helmet

The Helmet package helps to secure the app by setting various HTTP headers. First, let’s install the package.

npm i --save helmet

Now let’s create a global middleware using the following command.

nest g mi app

Now place the following code in the app.middleware.ts file.

import { INestApplication } from "@nestjs/common";
import * as helmet from 'helmet';

export function middleware(app: INestApplication): INestApplication {
 
  const isProduction = (process.env.NODE_ENV === 'production')

  app.use(helmet({ contentSecurityPolicy: isProduction }))

  return app;
}

And open the main.ts file and call the middleware function.

import { NestFactory } from '@nestjs/core';
import { middleware } from './app.middleware';
import { AppModule } from './app.module';

declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  middleware(app)

  await app.listen(3000);

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

Now to set the environment, open the package.json and modify start:dev and start:prod scripts as follows.

"start:dev": "NODE_ENV=development nest build --webpack --webpackPath webpack-hmr.config.js --watch",
"start:prod": "NODE_ENV=production node dist/main"

CSRF Protection

Since we’re not using cookies, CSRF is not really required.

Preventing Brute-force Attacks

To prevent brute-force attacks, let’s install the throttler package.

npm i --save @nestjs/throttler

Then include the TTL and requests limit times in the auth.config.ts file as follows.

export const jwtConfig = {
    secret: "secretKey",
    expireTime: "1h",
    expireIgnore: false
}

export const bruteForceLimits = {
    requestLimit: 10,
    ttl: 60
}

Then modify the app.module.ts as follows.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { bruteForceLimits } from './config/auth.config';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    AuthModule, 
    UsersModule,
    ThrottlerModule.forRoot({
      ttl: bruteForceLimits.ttl,
      limit: bruteForceLimits.requestLimit
    })
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_GUARD,
      useClass: ThrottlerGuard
    }
  ],
})
export class AppModule {}

CORS Enabling

Insert CORS config into the auth.config.ts as bellow.

export const jwtConfig = {
    secret: "l0XNT38sJ/OkVVpKTPNixGyH2SW5yF1NJqB9BAGczf1JKHIjenyqaQPOX9Tt9LBC3WHCoG08yhZe+MkQtATYgr5dLhFoTifsczfXNNMBTrXmJN5DV+WzesYS/daFMDC0vXmG/20ImrFsw22EKDWl4+VDAE1slVx/B41t5gNGt4ffd0UPE0wpekd23FOECD0EoTCLYsM7nSnMhUlKB4ONvAlOgObXLAgCgMkDe1g69kspxT1ev7/MyXv+xDRUikJgvPOuy7lZVMQ5eOC4ouELNT5L18yc9hbYEfQXDsUe6zCN6DNbASCYt2Eg/ki2nwpJb+NUT69ObWzxG9ZGJpgrqA==",
    expireTime: "1h",
    expireIgnore: false
}

export const bruteForceLimits = {
    requestLimit: 10,
    ttl: 60
}

export const corsConfig = {
    origin: "*",
    methods: 'GET, PUT, POST, DELETE',
    allowedHeaders: 'Content-Type, Authorization'
}

Then modify the app.middleware.ts as below.

import { INestApplication } from "@nestjs/common";
import * as helmet from 'helmet';
import { corsConfig } from "./config/auth.config";

export function middleware(app: INestApplication): INestApplication {
 
  const isProduction = (process.env.NODE_ENV === 'production')

  app.use(helmet({ contentSecurityPolicy: isProduction }))
  app.enableCors({ origin: corsConfig.origin, methods: corsConfig.methods, allowedHeaders: corsConfig.allowedHeaders });

  return app;
}

Environmental Files

First, you should install the following packages before creating environmental files.

npm i --save @nestjs/config

Then create developmnt.env and production.env files in your root folder.
And let’s move the origin configuration to the development.env file.

ORIGIN=http://localhost:3000

Now open the auth.config.ts file and modify it as follows.

export const jwtConfig = {
    secret: "secretKey",
    expireTime: "1h",
    expireIgnore: false
}

export const bruteForceLimits = {
    requestLimit: 10,
    ttl: 60
}

export const corsConfig = {
    methods: 'GET, PUT, POST, DELETE',
    allowedHeaders: 'Content-Type, Authorization'
}

Now open the app.module.ts file and modify it as follows to import the env variables.

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { UsersModule } from './users/users.module';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { bruteForceLimits } from './config/auth.config';
import { APP_GUARD } from '@nestjs/core';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({ envFilePath: `${process.env.NODE_ENV || 'development'}.env`, isGlobal: true }),
    AuthModule, 
    UsersModule,
    ThrottlerModule.forRoot({
      ttl: bruteForceLimits.ttl,
      limit: bruteForceLimits.requestLimit
    })
  ],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_GUARD,
      useClass: ThrottlerGuard
    }
  ],
})
export class AppModule {}

Finally, open the app.middleware.ts file and insert the origin from the env.

import { INestApplication } from "@nestjs/common";
import * as helmet from 'helmet';
import { corsConfig } from "./config/auth.config";

export function middleware(app: INestApplication): INestApplication {
 
  const isProduction = (process.env.NODE_ENV === 'production')

  app.use(helmet({ contentSecurityPolicy: isProduction }))
  app.enableCors({ origin: process.env.ORIGIN, methods: corsConfig.methods, allowedHeaders: corsConfig.allowedHeaders });

  return app;
}

Remember to add everything to the production.env as well before running the production build.

Compression

It’s important to add compression so the response body will be smaller and the app will be speeder. For adding compression, you need to install following package.

npm i --save compression

And then modify the app.middleware.ts file as follows.

import { INestApplication } from "@nestjs/common";
import * as helmet from 'helmet';
import { corsConfig } from "./config/auth.config";
import * as compression from 'compression';

export function middleware(app: INestApplication): INestApplication {
 
  const isProduction = (process.env.NODE_ENV === 'production')

  app.use(helmet({ contentSecurityPolicy: isProduction }))
  app.use(compression())

  app.enableCors({ origin: process.env.ORIGIN || '*', methods: corsConfig.methods, allowedHeaders: corsConfig.allowedHeaders })

  return app;
}

So that’s it

If you have any suggestions or questions about this guide, comment here or send me an email.

2 thoughts on “NestJS: Building the Base

Leave a Reply

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

Back to top