2 years ago
#33845

Henrique Ramos
NestJs Authentication Tutorial always returns 401 Unauthorized after implementing local strategy (When using browser)
What I want to do is a simple authentication using passport as this tutorial suggests: https://docs.nestjs.com/techniques/authentication
I followed this tutorial all along and works when i use Insomnia, Swagger or Postman. Later I created my front-end in react but the requests always returns
POST http://localhost:3333/auth/login 401 (Unauthorized)
{statusCode: 401, message: 'Unauthorized'}
.
Other routes like /user/getAll
work normally in swagger/postman and in the browser. But the auth route auth/login
only works in swagger/postman
Am I missing something here?
I looking for a solution for 4 hours and all the solutions that I found did not work in my project.
main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const corsOptions = {
origin: '*',
credentials: true,
allowedHeaders: 'Content-Type, Accept, Origin',
preflightContinue: false,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
};
app.enableCors(corsOptions);
app.use(helmet());
app.use(cookieParser());
// app.use(csurf());
const config = new DocumentBuilder()
.setTitle('Nyx Swagger')
.setDescription('The Nyx API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
app.useGlobalPipes(new ValidationPipe());
await app.listen(process.env.PORT || 3333);
}
bootstrap();
app.module.ts
@Module({
imports: [
MongooseModule.forRoot(
'mongodb+srv://USERNAME:PASSWORD@db-beta.6pfkk.mongodb.net/db-beta?retryWrites=true&w=majority',
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true,
},
),
ThrottlerModule.forRoot({
ttl: 60,
limit: 10,
}),
AuthModule,
UsersModule,
],
controllers: [AppController],
providers: [
LocalStrategy,
],
})
export class AppModule {}
app.controller.ts
@Controller()
export class AppController {
constructor(private authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('auth/login')
async login(
@Body() _: MakeAuthDto,
@Request() req,
@Res({ passthrough: true }) res,
) {
const access_token = await this.authService.login(req.user, req.ip);
res.cookie('jwt', access_token);
return req.user;
}
}
auth.module.ts
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: process.env.JWTSECRET,
signOptions: { expiresIn: '7d' },
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
auth.service.ts
@Injectable()
export class AuthService {
constructor(
private usersService: UsersService,
private jwtService: JwtService,
) {}
async validateUser(email: string, pass: string): Promise<UserDocument | any> {
const user = await this.usersService.findOne({ email } as any, true);
if (
user &&
(await user.compareHash(pass)) &&
user.hasAccess &&
!user.deleted
) {
const {
password,
verificationCode,
ips,
deleted,
hasAccess,
usageTerms,
usageTermsHistory,
...result
} = user.toObject();
return result;
}
return null;
}
async login(user: UserDocument, ip: string): Promise<string> {
const payload = {
email: user.email,
sub: user._id,
name: user.name,
roles: user.roles,
};
await this.usersService.updateLastLogin(user._id, ip);
return this.jwtService.sign(payload);
}
}
jwt.strategy.ts
const cookieExtractor = function (req) {
let token = null;
if (req && req.cookies) {
token = req.cookies['jwt'];
}
return token;
};
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromExtractors([cookieExtractor]),
ignoreExpiration: false,
secretOrKey: process.env.JWTSECRET,
});
}
async validate(payload: any) {
return {
_id: payload.sub,
name: payload.name,
email: payload.email,
roles: payload.roles,
};
}
}
local.strategy.ts
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({ usernameField: 'email' });
}
async validate(email: string, password: string): Promise<UserDocument> {
const user = await this.authService.validateUser(email, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
front-end request
export const AuthAPI = {
async login(data) {
const response = await fetch(`${API_URL}/auth/login`, {
method: "POST",
headers: { "Content-type": "application/json", accept: "*/*" },
// credentials: "include",
body: JSON.stringify(data),
});
const json = await response.json();
return json;
},
};
Prints:
reactjs
nestjs
passport.js
passport-local
0 Answers
Your Answer