Déclaration des routes d’auth, validation des données, gestion des erreurs et retours structurés.
Dans ce chapitre, tu vas découvrir comment exposer deux routes essentielles dans ton module d’authentification :
En parallèle, tu verras comment structurer tes DTOs avec class-validator et activer la ValidationPipe globale pour protéger automatiquement ton API.
On commence par le contrôleur qui gère les requêtes HTTP.
Chaque méthode utilise un DTO pour typer et valider le corps de la requête.
1import {2Body,3Controller,4Post,5} from '@nestjs/common'6import { AuthService } from './auth.service'7import { CreateUserDto } from './dto/create-user.dto'8import { LogUserDto } from './dto/log-user.dto'910@Controller('auth')11export class AuthController {12constructor(private readonly authService: AuthService) {}1314@Post('register')15async register(16@Body() registerBody: CreateUserDto,17) {18return this.authService.register({ registerBody })19}2021@Post('login')22async login(@Body() authBody: LogUserDto) {23return this.authService.login({ authBody })24}25}
@Controller('auth')
: préfixe /auth
pour toutes les routes.@Post('register')
et @Post('login')
: méthodes HTTP dédiées.@Body()
est typé par un DTO qui déclenche la validation.On verra dans la section suivante comment définir ces DTOs.
Les DTOs (Data Transfer Objects) centralisent la structure et les règles de validation.
1import {2IsEmail,3IsNotEmpty,4IsString,5MinLength,6} from 'class-validator'78export class CreateUserDto {9@IsEmail({}, { message: 'Tu dois fournir une adresse email valide.' })10email: string1112@IsNotEmpty()13@MinLength(6, {14message: 'Ton mot de passe doit faire au moins 6 caractères.',15})16password: string1718@IsString({ message: 'Le prénom est requis.' })19firstName: string20}
@IsEmail()
: vérifie le format d’email.@MinLength(6)
: impose une longueur minimale sur le mot de passe.1import {2IsEmail,3IsNotEmpty,4} from 'class-validator'56export class LogUserDto {7@IsEmail({}, { message: 'Email invalide.' })8email: string910@IsNotEmpty({ message: 'Le mot de passe ne peut pas être vide.' })11password: string12}
Pour que NestJS applique automatiquement la validation des DTOs, il suffit d’ajouter la ValidationPipe dans le fichier principal de ton app.
1import { ValidationPipe } from '@nestjs/common'2import { NestFactory } from '@nestjs/core'3import { AppModule } from './app.module'45async function bootstrap() {6const app = await NestFactory.create(AppModule)78app.useGlobalPipes(9new ValidationPipe({10whitelist: true,11forbidNonWhitelisted: true,12}), // ^? Enlève automatiquement les props non déclarées13)1415await app.listen(3000)16}17bootstrap()
whitelist: true
: supprime les champs non définis dans le DTO.forbidNonWhitelisted: true
: renvoie une erreur si des props inattendues sont envoyées.Cette configuration renforce ta sécurité en ne laissant passer que les données explicitement déclarées dans tes DTOs.
On ne va pas entrer dans tous les détails, mais voici la structure générale :
1import { Injectable, UnauthorizedException } from '@nestjs/common'2import { JwtService } from '@nestjs/jwt'3import * as bcrypt from 'bcrypt'4import { PrismaService } from 'src/prisma/prisma.service'5import { CreateUserDto } from './dto/create-user.dto'6import { LogUserDto } from './dto/log-user.dto'78@Injectable()9export class AuthService {10constructor(11private prisma: PrismaService,12private jwtService: JwtService,13) {}1415async register({ registerBody }: { registerBody: CreateUserDto }) {16const { email, password, firstName } = registerBody17const existing = await this.prisma.user.findUnique({ where: { email } })18if (existing) {19throw new UnauthorizedException('Email déjà utilisé.')20}21const hash = await bcrypt.hash(password, 10)22const user = await this.prisma.user.create({23data: { email, password: hash, firstName },24})25const payload = { sub: user.id, email: user.email }26return { access_token: this.jwtService.sign(payload) }27}2829async login({ authBody }: { authBody: LogUserDto }) {30const user = await this.prisma.user.findUnique({31where: { email: authBody.email },32})33if (!user || !(await bcrypt.compare(authBody.password, user.password))) {34throw new UnauthorizedException('Identifiants invalides.')35}36const payload = { sub: user.id, email: user.email }37return { access_token: this.jwtService.sign(payload) }38}39}
bcrypt.compare
à la connexion.JwtService
de @nestjs/jwt.Tu peux utiliser Postman ou Insomnia pour valider :
/auth/register
avec un corps conforme à CreateUserDto
./auth/login
avec un corps conforme à LogUserDto
.Tu devrais recevoir un objet { access_token: "..." }
si tout se passe bien.
lastName
dans CreateUserDto
:
@IsString()
et teste avec ValidationPipe.forbidNonWhitelisted
:
foo: "bar"
) et observe l’erreur.JwtAuthGuard
pour sécuriser la route GET /auth
.