2

I'm trying to implement RS256 JWT tokens in nestjs backend. I followed the example provided in nestjs documentation.

In my module I register the JwtModule with my private key:

@Module({
    imports: [
       PassportModule.register({ defaultStrategy: 'jwt' }),
       JwtModule.register({
         secretOrPrivateKey: extractKey(`${process.cwd()}/keys/jwt.private.key`),
         signOptions: {
            expiresIn: 3600,
         },
       }),
    ],
    controllers: [AuthController],
    providers: [AuthService, JwtStrategy, HttpStrategy],
})
export class AuthModule {}

I'm able to call auth/token endpoint and get the token but when I try to access guarded endpoint I always get 401.

Below you can find my custom JwtStrategy:

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
   constructor(private readonly authService: AuthService) {
      super({
          jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          secretOrKey: extractKey(`${process.cwd()}/keys/jwt.public.key`),
      });
   }

   async validate(payload: JwtPayload) {
       console.log('JwtStrategy');
       const user = await this.authService.validateUser(payload);
       if (!user) {
           throw new UnauthorizedException();
       }
       return user;
   }
}

And guarded endpoint:

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

   @Get('token')
   async createToken(): Promise<any> {
      return await this.authService.createToken();
   }

   @Get('data')
   @UseGuards(AuthGuard())
   findAll() {
      console.log('Guarded endpoint');
      // This route is restricted by AuthGuard
      // JWT strategy
   }
}

I assume that when I call the auth/data I should see in the console at least the "JwtStrategy" string that I log in the validate method. Unfortunately it never shows up. Why the validate method is never called?

Please find the codesandbox below

Edit Nest.js JWT Auth

jmazur
  • 125
  • 1
  • 4
  • 12

3 Answers3

6

You have to specify RS256 as the algorithm for in both the JwtModule and the JwtStrategy:

export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: publicKey,
      algorithms: ['RS256'],
      ^^^^^^^^^^^^^^^^^^^^^^
    });

and

JwtModule.register({
  secretOrPrivateKey: privateKey,
  signOptions: {
    expiresIn: 3600,
    algorithm: 'RS256',
    ^^^^^^^^^^^^^^^^^^^
  },
}),
Kim Kern
  • 54,283
  • 17
  • 197
  • 195
  • The example in your codesandbox also works for me. But it implements regular HS256 tokens. As I wrote in my question problem is with RS256 tokens - so signed with RSA certificate. – jmazur Mar 11 '19 at 08:04
  • Please have a look at my code sandbox - I've added a link in my question. – jmazur Mar 11 '19 at 08:25
  • Sorry, my previous answer was incorrect. See my edit – Kim Kern Mar 11 '19 at 12:36
  • Besides providing the algorith name in JwtModule and JwtStrategy I would only add that crucial is to have also keys in proper format. Private and public keys must be both in RSA format. Mine public key was provided in SSH2 format and thats why it was not working. – jmazur Mar 11 '19 at 13:56
0

Not sure if it works but you can try this

@UseGuards(AuthGuard('jwt'))

above your protected route.

Chetan Jain
  • 236
  • 6
  • 16
0

It's quite possible that the public key and/or private key files were not generated in RS256 format.

I'd recommend trying the following:

https://gist.github.com/ygotthilf/baa58da5c3dd1f69fae9

Adam W. Dennis
  • 476
  • 4
  • 8