I have the following error and I don't know why it happens. Could you help me
ERROR [ExceptionHandler] JwtStrategy requires a secret or key TypeError: JwtStrategy requires a secret or key at new JwtStrategy (C:\Users\wapg2\OneDrive\Productos\node_modules\passport-jwt\lib\strategy.js:45:15)
Auth controler:
import { Controller, Get, Post, UseGuards } from '@nestjs/mon';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { User, Auth } from 'src/mon/decorators';
import { Usuario } from 'src/usuarios/entities';
import { AuthService } from './auth.service';
import { JwtAuthGuard, LocalAuthGuard } from './guards';
@ApiTags('Auth routes')
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@UseGuards(LocalAuthGuard) //Aca usamos las estrategias
@Post('login')
//Passport crea automáticamente un objeto user, según el valor que devolvemos del método validate(), y lo asigna al objeto Request o req.user
login(@User() usuario: Usuario) {
const data = this.authService.login(usuario);
return {
message: 'Login exitoso',
data,
};
}
//Esta ruta se vuelve privada al usar JwtAuthGuard
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@Get('profile')
profile(@User() usuario: Usuario) {
return {
message: 'Petición correcta',
usuario,
};
}
@Auth() //-> decorador creado por nosotros para reducir @UseGuards(JwtAuthGuard) y @ApiBearerAuth()
@Get('refresh')
refreshToken(@User() usuario: Usuario) {
const data = this.authService.login(usuario);
return {
message: 'Refresh exitoso',
data,
};
}
}
Auth Service
import { Injectable } from '@nestjs/mon';
import { pare } from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { Usuario } from 'src/usuarios/entities';
import { UsuariosService } from 'src/usuarios/usuarios.service';
import { response } from 'express';
@Injectable()
export class AuthService {
constructor(
//Inyectamos UsuariosService y JwtService para usar las funciones que ofrecen. Estos servicios los podemos usar gracias a que hemos inyectado los módulos UserModule y JwtModule en el AuthModule. Tambien es posible usar el servicio UsuariosService gracias a que hemos exportado dicho servicio en el UsuariosModule (exports: [UsuariosService])
private readonly usuarioService: UsuariosService,
private readonly jwtService: JwtService,
) {}
async validateUser(email: string, password: string): Promise<any> {
const usuario = await this.usuarioService.buscarPorEmail({ email });
console.log(usuario);
if (usuario && (await pare(password, usuario.contrasena))) {
const { contrasena, ...usuarioSinContrasena } = usuario;
return usuarioSinContrasena;
}
return null;
}
//login crea el token JWT
login(usuario: Usuario) {
const { id } = usuario; //destructuración del objet user. Sacamos el id del retsto de los datos del user (...rest)
//creamos la info del payload del jwt. el sub va a servir para identificar a cada usuario
const payload = { sub: id };
return {
usuario,
accesToken: this.jwtService.sign(payload), //Generamos el token
};
}
}
Auth Module:
import { Module } from '@nestjs/mon';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy, LocalStrategy } from './strategies';
import { JWT_SECRET } from '../config/constants';
import { UsuariosModule } from 'src/usuarios/usuarios.module';
@Module({
imports: [
PassportModule.register({
defaultStrategy: 'jwt',
}),
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get<string>(JWT_SECRET),
signOptions: { expiresIn: '60m' }, //Tiempo en el que expira el token
}),
}),
UsuariosModule,
], //<-- se inportan los servicios y todo lo que se necesita de passport
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
Here is my jwtStrtegy
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from "passport-jwt";
import { JWT_SECRET } from "src/config/constants";
import { UserService } from "src/user/user.service";
import { Injectable } from '@nestjs/mon';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy){
constructor(
private readonly userService: UserService,
private readonly config: ConfigService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: config.get<string>(JWT_SECRET),
});
}
async validate(payload: any) {
const { sub: id } = payload;
return await this.userService.getOne(id);
}
}
I have the following error and I don't know why it happens. Could you help me
ERROR [ExceptionHandler] JwtStrategy requires a secret or key TypeError: JwtStrategy requires a secret or key at new JwtStrategy (C:\Users\wapg2\OneDrive\Productos\node_modules\passport-jwt\lib\strategy.js:45:15)
Auth controler:
import { Controller, Get, Post, UseGuards } from '@nestjs/mon';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { User, Auth } from 'src/mon/decorators';
import { Usuario } from 'src/usuarios/entities';
import { AuthService } from './auth.service';
import { JwtAuthGuard, LocalAuthGuard } from './guards';
@ApiTags('Auth routes')
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@UseGuards(LocalAuthGuard) //Aca usamos las estrategias
@Post('login')
//Passport crea automáticamente un objeto user, según el valor que devolvemos del método validate(), y lo asigna al objeto Request o req.user
login(@User() usuario: Usuario) {
const data = this.authService.login(usuario);
return {
message: 'Login exitoso',
data,
};
}
//Esta ruta se vuelve privada al usar JwtAuthGuard
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@Get('profile')
profile(@User() usuario: Usuario) {
return {
message: 'Petición correcta',
usuario,
};
}
@Auth() //-> decorador creado por nosotros para reducir @UseGuards(JwtAuthGuard) y @ApiBearerAuth()
@Get('refresh')
refreshToken(@User() usuario: Usuario) {
const data = this.authService.login(usuario);
return {
message: 'Refresh exitoso',
data,
};
}
}
Auth Service
import { Injectable } from '@nestjs/mon';
import { pare } from 'bcryptjs';
import { JwtService } from '@nestjs/jwt';
import { Usuario } from 'src/usuarios/entities';
import { UsuariosService } from 'src/usuarios/usuarios.service';
import { response } from 'express';
@Injectable()
export class AuthService {
constructor(
//Inyectamos UsuariosService y JwtService para usar las funciones que ofrecen. Estos servicios los podemos usar gracias a que hemos inyectado los módulos UserModule y JwtModule en el AuthModule. Tambien es posible usar el servicio UsuariosService gracias a que hemos exportado dicho servicio en el UsuariosModule (exports: [UsuariosService])
private readonly usuarioService: UsuariosService,
private readonly jwtService: JwtService,
) {}
async validateUser(email: string, password: string): Promise<any> {
const usuario = await this.usuarioService.buscarPorEmail({ email });
console.log(usuario);
if (usuario && (await pare(password, usuario.contrasena))) {
const { contrasena, ...usuarioSinContrasena } = usuario;
return usuarioSinContrasena;
}
return null;
}
//login crea el token JWT
login(usuario: Usuario) {
const { id } = usuario; //destructuración del objet user. Sacamos el id del retsto de los datos del user (...rest)
//creamos la info del payload del jwt. el sub va a servir para identificar a cada usuario
const payload = { sub: id };
return {
usuario,
accesToken: this.jwtService.sign(payload), //Generamos el token
};
}
}
Auth Module:
import { Module } from '@nestjs/mon';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy, LocalStrategy } from './strategies';
import { JWT_SECRET } from '../config/constants';
import { UsuariosModule } from 'src/usuarios/usuarios.module';
@Module({
imports: [
PassportModule.register({
defaultStrategy: 'jwt',
}),
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get<string>(JWT_SECRET),
signOptions: { expiresIn: '60m' }, //Tiempo en el que expira el token
}),
}),
UsuariosModule,
], //<-- se inportan los servicios y todo lo que se necesita de passport
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
})
export class AuthModule {}
Here is my jwtStrtegy
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from "passport-jwt";
import { JWT_SECRET } from "src/config/constants";
import { UserService } from "src/user/user.service";
import { Injectable } from '@nestjs/mon';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy){
constructor(
private readonly userService: UserService,
private readonly config: ConfigService,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: config.get<string>(JWT_SECRET),
});
}
async validate(payload: any) {
const { sub: id } = payload;
return await this.userService.getOne(id);
}
}
Share
Improve this question
edited Feb 27, 2022 at 17:32
William Pineda MHA
asked Feb 27, 2022 at 17:21
William Pineda MHAWilliam Pineda MHA
2951 gold badge2 silver badges12 bronze badges
4
-
I'd guess that
config.get<string>(JWT_SECRET),
is the problem. TheJWT_SECRET
is probably the secret itself, not the config key of the secret. So set it just assecretOrKey: JWT_SECRET
. – Uroš Anđelić Commented Feb 27, 2022 at 17:54 -
Do you have a
.env
file with the valueJWT_SECRET="someString"
? – Jay McDoniel Commented Feb 27, 2022 at 18:37 - @JayMcDoniel Yes. I don't know what else to do – William Pineda MHA Commented Feb 27, 2022 at 18:43
-
From what's shown here, everything looks good. I'd double check your
ConfigModule
setup and make sure thatconfig.get('JWT_SECRET')
returns what you expect it to – Jay McDoniel Commented Feb 27, 2022 at 18:50
6 Answers
Reset to default 4You haven't posted the file where your LocalStrategy
definition is but I'm guessing the problem is you probably have imported the Strategy
dependency from passport-jwt
instead of passport-local
in that file.
You shouldn't import like this
import { ExtractJwt, Strategy } from 'passport-jwt';
Instead you should do it like this
import { Strategy } from 'passport-local';
With nestjs
you can create your own strategy file as jwt.stategy.ts
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/mon';
import { ConfigService } from '@nestjs/config';
import {Request} from 'express';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, "jwt") {
constructor(configService: ConfigService) {
super({
// get JWT from Header
// jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
// get JWT from cookie
jwtFromRequest: ExtractJwt.fromExtractors([
(request: Request) => (
request.cookies.jwt
)
]),
ignoreExpiration: false,
secretOrKey: configService.get<string>("JWT_SECRET"), // REQUIRED
});
}
async validate(payload: any) {
return payload;
}
}
And use guard as @UseGuards(AuthGuard("jwt"))
@UseGuards(AuthGuard("jwt"))
@ApiBearerAuth()
@Get('profile')
profile(@User() usuario: Usuario) {
return {
message: 'Petición correcta',
usuario,
};
}
The name "jwt"
is a reference to strategy name at definition:
PassportStrategy(Strategy, "jwt")
I find this example :
import { Injectable } from '@nestjs/mon';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
type JwtPayload = {
sub: string;
username: string;
};
@Injectable()
export class AccessTokenStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey:
'7sFHZrGLIMIwTotAEyNS/j4yUEW7OtYmGebnAKWQOBJ/kB+ur4XnGt1oxnRC9HUOUK+hBfcOmqw+BmlgXFB4zRzte6LRqvXlLrNiXO+REDKycfYBFywXtFQ65ZE0B5Z9EwFXaP29QysUSc2HxDeWIMzfl5nMYDj0TYHEYPJPs2Zb4hKNPIpHdA2e+8r6imFsD5C5vh0P3psnLTX8liWgkC+8ENf1YxiORqAMt9kQ9Ola7WSkaTKe6dqLKGHDMeICTw2YcCZ7+I9yT4Umgncqz78pAsBHDJPE/oFMtxw9/moCMoMH2D6dJ34R09OQ/gv8lwIjKZfBVGNsqxHW8vuppw==',
});
}
validate(payload: JwtPayload) {
return payload;
}
}
In my case i used this mand node -e "console.log(require('crypto').randomBytes(256).toString('base64'));"
to generate a random secret , you can use openssl to generate code .
Follow this tutorial :
https://www.elvisduru./blog/nestjs-jwt-authentication-refresh-token
The option secretOrKey
is required for the passport-jwt
package:
secretOrKey
is a string or buffer containing the secret (symmetric) or PEM-encoded public key (asymmetric) for verifying the token's signature. REQUIRED unlesssecretOrKeyProvider
is provided.
A sample config that uses an arbitrary value as secretOrKey
:
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'secret'; // arbitrary value used for verify JWT token
opts.issuer = 'accounts.examplesoft.';
opts.audience = 'yoursite';
If still facing the problem try this:
Ensure that the ConfigModule is properly imported and configured to load environment variables.
In your AuthModule, you should have:
ConfigModule.forRoot({
isGlobal: true,
}),
This makes sure that the environment variables are accessible throughout your application.