Search code examples
controllerrequesthttp-headersnestjs

How to get JWT token from headers in controller


Please, help me to find how to optimize my code. I need to limit the data for logged user. To do that, I need to get UUID from JWT token from Request. But I don't like my approach because I have duplicates of code:

const jwt = request.headers.authorization.replace('Bearer ', '');
const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };

Any one know how I can optimize that?

Here is my controller's code.

import { Controller, Get, Put, Body, Param, UseGuards, Req } from '@nestjs/common';
import { SettingService } from '../services';
import { AuthGuard } from '@nestjs/passport';
import { ResultInterface } from '../interfaces';
import { Request } from 'express';
import { JwtService } from '@nestjs/jwt';

@Controller('settings')
export class SettingController {
  /**
   * @param service
   * @param jwtService
   */
  constructor(private readonly service: SettingService,
              private readonly jwtService: JwtService) {
  }

  @UseGuards(AuthGuard('jwt'))
  @Get()
  async findAll(@Req() request: Request): Promise<ResultInterface> {
    const jwt = request.headers.authorization.replace('Bearer ', '');
    const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
    const data = await this.service.findAll(json.uuid);
    return { rows: data };
  }

  @UseGuards(AuthGuard('jwt'))
  @Get(':id')
  async findOne(@Param('id') id: number, @Req() request: Request): Promise<ResultInterface> {
    const jwt = request.headers.authorization.replace('Bearer ', '');
    const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
    const data = await this.service.findOneById(id, json.uuid);
    return { row: data };
  }

  @UseGuards(AuthGuard('jwt'))
  @Put()
  update(@Body() data: any, @Req() request: Request): Promise<any> {
    const jwt = request.headers.authorization.replace('Bearer ', '');
    const json = this.jwtService.decode(jwt, { json: true }) as { uuid: string };
    return this.service.update(data, json.uuid);
  }
}

Solution

  • In order to make your code more readable and transparent, you can create a @AuthUser() decorator and reuse it across all of your controllers. When you are using AuthGuard('jwt') you already are decoding the token and if you are using jwt.decode function again you double decode the token.

    I attached below and example of user decorator and order controller function that returns all my orders.

    user.decorator.ts

    import { createParamDecorator } from '@nestjs/common';
    
    export const AuthUser = createParamDecorator((data, req) => {
      return req.user;
    });
    

    order.controller.ts

     @ApiOperation({ title: 'Get my orders' })
     @Get('/me')
     @UseGuards(AuthGuard('jwt'))
     async findMyOrders(@AuthUser() user: any): Promise<Order[]> {
       return this.orderService.findbyUserId(user._id);
     }