Search code examples
jwtpassport.jsnestjspassport-jwtnestjs-jwt

Nestjs, can't verify jwt


I am sending request on the frontend and it returns 401 Unathorized, when I console.log(headers) on controller, without guard x-access-token exists, when I remove guard everything works fine and image url is sent back to frontend.

const response = await axios
          .get(
            '/auth/avatar',
            {
              headers: {
                'x-access-token': sessionStorage.getItem('token')
              },
              params: {
                username: sessionStorage.getItem('username')
              }
            }
          )

        console.log(response.data);

On /auth controller

@Get('/avatar')
  @UseGuards(AuthGuard('jwt'))
  getAvatar(
    @Query('username') username: string,
  ): Promise<string> {
    return this.authService.getAvatar(username);
  }

Service:

getAvatar(username: string): Promise<string> {
    return this.usersRepository.getAvatarUrl(username);
  }

repository:

async getAvatarUrl(username: string): Promise<string> {
    const user = await this.findOne({ where: { username } });
    return user.documentLocation;
  }

jwt-strategy

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { JwtPayload } from './jwt-payload.interface';
import { User } from './user.entity';
import { UsersRepository } from './users.repository';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    @InjectRepository(UsersRepository)
    private usersRepository: UsersRepository,
    private configService: ConfigService,
  ) {
    super({
      secretOrKey: configService.get('JWT_SECRET'),
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    });
  }

  async validate(payload: JwtPayload): Promise<User> {
    const { username } = payload;
    const user: User = await this.usersRepository.findOne({ username });

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

    return user;
  }
}

auth module:

JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        secret: configService.get('JWT_SECRET'),
        signOptions: {
          expiresIn: 3600,
        },
      }),
    }),

Solution

  • You have the wrong header. In your example you fetch with auth headers:

    headers: {
        'x-access-token': sessionStorage.getItem('token')
    },
    

    But in jwt-stategy is enabled auth with bearer token Authorization: Bearer ${token}.

    You can fix it with update jwt-strategy to:

    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { ConfigService } from '@nestjs/config';
    import { PassportStrategy } from '@nestjs/passport';
    import { InjectRepository } from '@nestjs/typeorm';
    import { ExtractJwt, Strategy } from 'passport-jwt';
    import { JwtPayload } from './jwt-payload.interface';
    import { User } from './user.entity';
    import { UsersRepository } from './users.repository';
    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor(
        @InjectRepository(UsersRepository)
        private usersRepository: UsersRepository,
        private configService: ConfigService,
      ) {
        super({
          secretOrKey: configService.get('JWT_SECRET'),
          jwtFromRequest: ExtractJwt.fromHeader('x-auth-token'),
        });
      }
    
      async validate(payload: JwtPayload): Promise<User> {
        const { username } = payload;
        const user: User = await this.usersRepository.findOne({ username });
    
        if (!user) {
          throw new UnauthorizedException();
        }
    
        return user;
      }
    }
    
    

    Or:

    await axios
              .get(
                '/auth/avatar',
                {
                  headers: {
                    'Authorization': `Bearer ${sessionStorage.getItem('token')}`
                  },
                  params: {
                    username: sessionStorage.getItem('username')
                  }
                }
              )