{
  "slug": "Authentication-and-Authorization-in-NestJS---A-Comprehensive-Overview-66495810c5b4",
  "title": "Authentication and Authorization in NestJS : A Comprehensive Overview",
  "subtitle": "NestJS, a progressive Node.js framework, offers robust capabilities for implementing authentication and authorization in web applications…",
  "excerpt": "NestJS, a progressive Node.js framework, offers robust capabilities for implementing authentication and authorization in web applications…",
  "date": "2024-07-01",
  "tags": [
    "Node.js",
    "Security"
  ],
  "readingTime": "8 min",
  "url": "https://medium.com/@mobinshaterian/authentication-and-authorization-in-nestjs-a-comprehensive-overview-66495810c5b4",
  "hero": "https://cdn-images-1.medium.com/max/800/1*u_0KhLB7v26vYkXvpTtqig.jpeg",
  "content": [
    {
      "type": "paragraph",
      "html": "NestJS, a progressive Node.js framework, offers robust capabilities for implementing authentication and authorization in web applications. This essay examines the process of integrating these crucial security features using NestJS, focusing on user management, secure password handling, and JSON Web Token (JWT) implementation."
    },
    {
      "type": "paragraph",
      "html": "The process begins with the generation of an Auth module, complete with associated controller and service components. This modular approach aligns with NestJS’s architectural principles, promoting code organization and maintainability. The Auth module is then integrated into the application’s main module, establishing a foundation for user-related functionalities."
    },
    {
      "type": "paragraph",
      "html": "User management is implemented through a dedicated Users entity, which includes fields for unique identifiers, usernames, passwords, and creation timestamps. This entity is managed via a UsersRepository, which extends TypeORM’s Repository class, providing an abstraction layer for database operations."
    },
    {
      "type": "paragraph",
      "html": "A critical aspect of user authentication is secure password handling. The implementation utilizes bcrypt, a well-regarded hashing function, to generate salted and hashed passwords before storage. This approach significantly enhances security by ensuring that plain-text passwords are never stored in the database."
    },
    {
      "type": "paragraph",
      "html": "The authentication flow comprises two main operations: user sign-up and sign-in. The sign-up process involves creating new user records with validated credentials, while sign-in verifies provided credentials against stored data. Both operations are exposed through the AuthController, which delegates to the AuthService for business logic execution."
    },
    {
      "type": "paragraph",
      "html": "Input validation is enforced using class-validator decorators, ensuring that usernames and passwords meet specified criteria. This includes length constraints and complexity requirements for passwords, thereby enhancing the overall security posture of the application."
    },
    {
      "type": "paragraph",
      "html": "The implementation of JSON Web Tokens (JWT) marks a significant step in the authorization process. JWTs are generated upon successful authentication and serve as secure, stateless session management tools. The JwtModule is configured with a secret key and token expiration time, providing a balance between security and user experience."
    },
    {
      "type": "paragraph",
      "html": "A custom JWTStrategy is implemented, extending Passport’s strategy pattern. This strategy is responsible for JWT validation and user retrieval based on the token payload. The integration of Passport and JWT in NestJS creates a seamless authentication flow, where valid tokens grant access to protected resources."
    },
    {
      "type": "paragraph",
      "html": "The essay concludes by discussing the integration of JWT-based authentication with the application’s task management feature. By applying the AuthGuard to the TasksController, all task-related endpoints are secured, ensuring that only authenticated users can access these resources."
    },
    {
      "type": "paragraph",
      "html": "In conclusion, this comprehensive approach to authentication and authorization in NestJS demonstrates the framework’s flexibility and power in building secure web applications. By leveraging TypeORM for data persistence, Passport for authentication strategies, and JWT for stateless authorization, developers can create robust, scalable systems that prioritize security without compromising on functionality or performance."
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*u_0KhLB7v26vYkXvpTtqig.jpeg",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 1024,
      "height": 1024
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Generate Auth module controller and service"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "nest g module authnest g service auth --no-specnest g controller auth --no-specyarn start:dev"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Source Code :"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Initial Auth Folder"
    },
    {
      "type": "paragraph",
      "html": "app.module.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Module({\n  imports: [...TasksModule, AuthModule,],\n})"
    },
    {
      "type": "paragraph",
      "html": "auth.module.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Module\n}\nfrom '@nestjs/common';\nimport {\n  AuthService\n}\nfrom './auth.service';\nimport {\n  AuthController\n}\nfrom './auth.controller';\nimport {\n  TypeOrmModule\n}\nfrom '@nestjs/typeorm';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\n@Module({\n  imports: [TypeOrmModule.forFeature([Users])], providers: [AuthService, UsersRepository],\n  controllers: [AuthController],\n})\nexport class AuthModule {\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.controller.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Controller\n}\nfrom '@nestjs/common';\n@Controller('auth')\nexport class AuthController {\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.service.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable\n}\nfrom '@nestjs/common';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  InjectRepository\n}\nfrom '@nestjs/typeorm';\n@Injectable()\nexport class AuthService {\n  constructor(@InjectRepository(UsersRepository) private userRepository: UsersRepository,) {\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.repository.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable\n}\nfrom '@nestjs/common';\nimport {\n  DataSource, Repository\n}\nfrom 'typeorm';\nimport {\n  Users\n}\nfrom './user.entity';\n@Injectable()\nexport class UsersRepository extends Repository<Users> {\n  constructor(private ds: DataSource) {\n    super(Users, ds.createEntityManager());\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.entity.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Column, Entity, PrimaryGeneratedColumn\n}\nfrom 'typeorm';\n@Entity()\nexport class Users {\n  @PrimaryGeneratedColumn('uuid') id: string;\n  @Column() username: string;\n  @Column() password: string;\n  @Column() created_at: Date;\n}"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*7618VfpdsQt2ijdgqb0nog.jpeg",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 1024,
      "height": 1024
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Create User or signup"
    },
    {
      "type": "paragraph",
      "html": "add migration sql"
    },
    {
      "type": "code",
      "lang": "sql",
      "code": "-- liquibase formatted sql\n-- changeset mobin:2\nCREATE TABLE IF NOT EXISTS \"users\" (\n    \"id\" UUID NOT NULL DEFAULT gen_random_uuid(),\n    \"username\" TEXT NOT NULL,\n    \"password\" TEXT NOT NULL,\n    \"created_at\" TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n    PRIMARY KEY (\"id\")\n);\n\nCREATE INDEX ON \"users\" (\"id\");\n\n-- rollback DROP TABLE \"tasks\";"
    },
    {
      "type": "paragraph",
      "html": "apply update"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "sudo\ndocker-compose -f docker-compose.yml exec liquibase /bin/shliquibase update\n--url=jdbc:postgresql://postgres-tasks:5432/task?currentSchema=public --changelog-file=changelog.xml\n--username=user --password=pass"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*JdkYXNMGzfEGThJ7v_ObCQ.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 776,
      "height": 549
    },
    {
      "type": "paragraph",
      "html": "adminer"
    },
    {
      "type": "code",
      "lang": "text",
      "code": "http://127.0.0.1:10000/?pgsql=postgres-tasks&username=user&db=task&ns=public&table=users"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*TcbybjOfBRPohTdnMk3dgw.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 353,
      "height": 140
    },
    {
      "type": "paragraph",
      "html": "postman"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*fui0GUFHR_sXWE1DVIdeMw.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 1127,
      "height": 535
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*SC5RJTP5ActuJ7En8Go0Fw.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 711,
      "height": 219
    },
    {
      "type": "paragraph",
      "html": "dto"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "export class AuthCredentialsDto {\n  username: string;\n  password: string;\n}"
    },
    {
      "type": "paragraph",
      "html": "user.repository.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable\n}\nfrom '@nestjs/common';\nimport {\n  DataSource, Repository\n}\nfrom 'typeorm';\nimport {\n  Users\n}\nfrom './user.entity';\nimport {\n  AuthCredentialsDto\n}\nfrom './dto/auth-credentials.dto';\n@Injectable()\nexport class UsersRepository extends Repository<Users> {\n  constructor(private ds: DataSource) {\n    super(Users, ds.createEntityManager());\n  }\n  async createUser(authCredentialDto: AuthCredentialsDto): Promise<void> {\n    const {\n      username, password\n    }\n    = authCredentialDto;\n    const user = this.create({\n      username, password,\n    });\n    await this.save(user);\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.service.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable\n}\nfrom '@nestjs/common';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  InjectRepository\n}\nfrom '@nestjs/typeorm';\nimport {\n  AuthCredentialsDto\n}\nfrom './dto/auth-credentials.dto';\n@Injectable()\nexport class AuthService {\n  constructor(@InjectRepository(UsersRepository) private userRepository: UsersRepository,) {\n  }\n  async signUp(authCredentialsDto: AuthCredentialsDto): Promise<void> {\n    return this.userRepository.createUser(authCredentialsDto);\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "auth.controller.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Body, Controller, Post\n}\nfrom '@nestjs/common';\nimport {\n  AuthService\n}\nfrom './auth.service';\nimport {\n  AuthCredentialsDto\n}\nfrom './dto/auth-credentials.dto';\n@Controller('auth')\nexport class AuthController {\n  constructor(private authService: AuthService) {\n  }\n  @Post('/signup') async signUp(@Body() authCredentialsDto: AuthCredentialsDto): Promise<void> {\n    return this.authService.signUp(authCredentialsDto);\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "User Validation"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  IsString, Matches, MaxLength, MinLength\n}\nfrom 'class-validator';\nexport class AuthCredentialsDto {\n  @IsString() @MinLength(4) @MaxLength(20) username: string;\n  @IsString() @MinLength(8) @MaxLength(32)\n  @Matches(/((?=.*\\d)|(?=.*\\W+))(?![.\\n])(?=.*[A-Z])(?=.*[a-z]).*$/, {\n    message: 'Password too weak',\n  }) password: string;\n}"
    },
    {
      "type": "paragraph",
      "html": "This regular expression is typically used for password validation. Let’s break it down step by step:"
    },
    {
      "type": "paragraph",
      "html": "1. `/` at the start and end: These delimit the regular expression."
    },
    {
      "type": "paragraph",
      "html": "2. `((?=.*\\d)|(?=.*\\W+))`: This is a positive lookahead that ensures the string contains either:<br> — `(?=.*\\d)`: At least one digit<br> — OR<br> — `(?=.*\\W+)`: At least one non-word character (special character)"
    },
    {
      "type": "paragraph",
      "html": "3. `(?![.\\n])`: This is a negative lookahead that ensures the string doesn’t end with a dot or newline."
    },
    {
      "type": "paragraph",
      "html": "4. `(?=.*[A-Z])`: This is a positive lookahead that ensures the string contains at least one uppercase letter."
    },
    {
      "type": "paragraph",
      "html": "5. `(?=.*[a-z])`: This is a positive lookahead that ensures the string contains at least one lowercase letter."
    },
    {
      "type": "paragraph",
      "html": "6. `.*`: This matches any character (except newline) zero or more times."
    },
    {
      "type": "paragraph",
      "html": "7. `$`: This asserts the position at the end of the string."
    },
    {
      "type": "paragraph",
      "html": "In summary, this regular expression validates a string that meets the following criteria:<br>- Contains at least one digit or special character<br>- Does not end with a dot or newline<br>- Contains at least one uppercase letter<br>- Contains at least one lowercase letter<br>- Can contain any characters, and must be at the end of the string"
    },
    {
      "type": "paragraph",
      "html": "This type of regex is commonly used for ensuring password strength, requiring a mix of character types for security."
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Prevent repeated username"
    },
    {
      "type": "paragraph",
      "html": "entity"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Column, Entity, PrimaryGeneratedColumn\n}\nfrom 'typeorm';\n@Entity()\nexport class Users {\n  @PrimaryGeneratedColumn('uuid') id: string;\n  @Column({\n    unique: true\n  }) username: string;\n  @Column() password: string;\n  @Column() created_at: Date;\n}"
    },
    {
      "type": "paragraph",
      "html": "repository"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "async createUser(authCredentialDto: AuthCredentialsDto): Promise<void> {    const { username,\npassword } = authCredentialDto;    const user = this.create({      username,      password,    });\ntry {      await this.save(user);    } catch (error) {      console.error(error);      if\n(error.code === '23505') {        throw new ConflictException('Username already exists');      }\nelse {        throw new InternalServerErrorException();      }    }  }"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Using Bcrypt for store hash of password"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "yarn add bcrypt"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*DBz62sD5yKc75ZpXtjIQLQ.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 1103,
      "height": 97
    },
    {
      "type": "paragraph",
      "html": "repository"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "async createUser(authCredentialDto: AuthCredentialsDto): Promise<void> {    const { username,\npassword } = authCredentialDto;    const salt = await bycrypt.genSalt();    const hashedPassword =\nawait bycrypt.hash(password, salt);    const user = this.create({      username,      password:\nhashedPassword,    });    try {      await this.save(user);    } catch (error) {\nconsole.error(error);      if (error.code === '23505') {        throw new\nConflictException('Username already exists');      } else {        throw new\nInternalServerErrorException();      }    }  }"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Sign in"
    },
    {
      "type": "paragraph",
      "html": "controller"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Post('/signin') async signIn(@Body() authCredentialsDto: AuthCredentialsDto,): Promise<string> {\n  return this.authService.signIn(authCredentialsDto);\n}"
    },
    {
      "type": "paragraph",
      "html": "service"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "async signIn(authCredentialsDto: AuthCredentialsDto): Promise<string> {    return\nthis.userRepository.validateUserPassword(authCredentialsDto);  }"
    },
    {
      "type": "paragraph",
      "html": "repository"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "async validateUserPassword(    authCredentialDto: AuthCredentialsDto,  ): Promise<string> {    const\n{ username, password } = authCredentialDto;    const user = await this.findOne({ where: { username }\n});    if (user && (await bycrypt.compare(password, user.password))) {      return 'success';    }\nelse {      return 'Invalid credentials';    }  }"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "JWT"
    },
    {
      "type": "paragraph",
      "html": "install"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "yarn add @nestjs/jwt @nestjs/passport passport passport-jwt"
    },
    {
      "type": "paragraph",
      "html": "auth.model"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Module\n}\nfrom '@nestjs/common';\nimport {\n  AuthService\n}\nfrom './auth.service';\nimport {\n  AuthController\n}\nfrom './auth.controller';\nimport {\n  TypeOrmModule\n}\nfrom '@nestjs/typeorm';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  Users\n}\nfrom './user.entity';\nimport {\n  PassportModule\n}\nfrom '@nestjs/passport';\nimport {\n  JwtModule\n}\nfrom '@nestjs/jwt';\n@Module({\n  imports: [PassportModule.register({\n    defaultStrategy: 'jwt'\n  }), JwtModule.register({\n    secret: 'topSecret51', signOptions: {\n      expiresIn: 3600,\n    },\n  }), TypeOrmModule.forFeature([Users]),], providers: [AuthService, UsersRepository], controllers:\n  [AuthController],\n})\nexport class AuthModule {\n}"
    },
    {
      "type": "paragraph",
      "html": "jwt-payload.interface.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "export interface JwtPayload {\n  username: string;\n}"
    },
    {
      "type": "paragraph",
      "html": "controller"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Post('/signin') async signIn(@Body() authCredentialsDto: AuthCredentialsDto,): Promise<{\n  accessToken: string\n}\n> {\n  return this.authService.signIn(authCredentialsDto);\n}"
    },
    {
      "type": "paragraph",
      "html": "service"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable\n}\nfrom '@nestjs/common';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  InjectRepository\n}\nfrom '@nestjs/typeorm';\nimport {\n  AuthCredentialsDto\n}\nfrom './dto/auth-credentials.dto';\nimport {\n  JwtService\n}\nfrom '@nestjs/jwt';\nimport {\n  JwtPayload\n}\nfrom './jwt-payload.intreface';\n@Injectable()\nexport class AuthService {\n  constructor(@InjectRepository(UsersRepository) private userRepository: UsersRepository, private\n  jwtService: JwtService,) {\n  }\n  async signUp(authCredentialsDto: AuthCredentialsDto): Promise<void> {\n    return this.userRepository.createUser(authCredentialsDto);\n  }\n  async signIn(authCredentialsDto: AuthCredentialsDto,): Promise<{\n    accessToken: string\n  }\n  > {\n    if (await this.userRepository.validateUserPassword(authCredentialsDto)) {\n      const payload: JwtPayload = {\n        username: authCredentialsDto.username\n      };\n      const accessToken: string = this.jwtService.sign(payload);\n      return {\n        accessToken\n      };\n    }\n  }\n}"
    },
    {
      "type": "paragraph",
      "html": "repository"
    },
    {
      "type": "code",
      "lang": "javascript",
      "code": "async validateUserPassword(    authCredentialDto: AuthCredentialsDto,  ): Promise<boolean> {\nconst { username, password } = authCredentialDto;    const user = await this.findOne({ where: {\nusername } });    if (user && (await bycrypt.compare(password, user.password))) {      return true;\n} else {      return false;    }  }"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "JWT Validation"
    },
    {
      "type": "paragraph",
      "html": "Install package"
    },
    {
      "type": "code",
      "lang": "bash",
      "code": "yarn add @types/passport-jwt"
    },
    {
      "type": "paragraph",
      "html": "auth.module.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Module\n}\nfrom '@nestjs/common';\nimport {\n  AuthService\n}\nfrom './auth.service';\nimport {\n  AuthController\n}\nfrom './auth.controller';\nimport {\n  TypeOrmModule\n}\nfrom '@nestjs/typeorm';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  Users\n}\nfrom './user.entity';\nimport {\n  PassportModule\n}\nfrom '@nestjs/passport';\nimport {\n  JwtModule\n}\nfrom '@nestjs/jwt';\nimport {\n  JWTStrategy\n}\nfrom './jwt.strategy';\n@Module({\n  imports: [PassportModule.register({\n    defaultStrategy: 'jwt'\n  }), JwtModule.register({\n    secret: 'topSecret51', signOptions: {\n      expiresIn: 3600,\n    },\n  }), TypeOrmModule.forFeature([Users]),], providers: [AuthService, UsersRepository, JWTStrategy],\n  controllers: [AuthController], exports: [JWTStrategy, PassportModule],\n})\nexport class AuthModule {\n}"
    },
    {
      "type": "paragraph",
      "html": "jwt.strategy.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "import {\n  Injectable, UnauthorizedException\n}\nfrom '@nestjs/common';\nimport {\n  PassportStrategy\n}\nfrom '@nestjs/passport';\nimport {\n  ExtractJwt, Strategy\n}\nfrom 'passport-jwt';\nimport {\n  UsersRepository\n}\nfrom './users.repository';\nimport {\n  InjectRepository\n}\nfrom '@nestjs/typeorm';\nimport {\n  JwtPayload\n}\nfrom './jwt-payload.intreface';\nimport {\n  Users\n}\nfrom './user.entity';\n@Injectable()\nexport class JWTStrategy extends PassportStrategy(Strategy) {\n  constructor(@InjectRepository(UsersRepository) private userRepository: UsersRepository,) {\n    super({\n      secretOrKey: 'topSecret51', jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n    });\n  }\n  async validate(payload: JwtPayload): Promise<Users> {\n    const {\n      username\n    }\n    = payload;\n    const user: Users = await this.userRepository.findOne({\n      where: {\n        username\n      },\n    });\n    if (!user) {\n      throw new UnauthorizedException();\n    }\n    return user;\n  }\n}"
    },
    {
      "type": "heading",
      "level": 2,
      "text": "Add JWT to tasks"
    },
    {
      "type": "paragraph",
      "html": "tasks.module.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Module({\n  imports: [TypeOrmModule.forFeature([Tasks]), AuthModule], controllers: [TasksController],\n  providers: [TasksService, TaskRepository],\n})"
    },
    {
      "type": "paragraph",
      "html": "tasks.controller.ts"
    },
    {
      "type": "code",
      "lang": "typescript",
      "code": "@Controller('tasks')@UseGuards(AuthGuard())"
    },
    {
      "type": "paragraph",
      "html": "add jwt token to bearer"
    },
    {
      "type": "image",
      "src": "https://cdn-images-1.medium.com/max/800/1*xa60SBhwsTfOAU7L-4aAxg.png",
      "alt": "Authentication and Authorization in NestJS : A Comprehensive Overview",
      "caption": "",
      "width": 730,
      "height": 436
    }
  ]
}
