Episode ini membahas keamanan API NestJS: fundamentals security, autentikasi JWT dan guards, integrasi Passport dengan auth strategies, serta role-based access control dan permissions berbasis role.

API tanpa autentikasi adalah pintu terbuka. Episode 12 membangun lapisan keamanan pertama yang wajib ada: autentikasi dengan JWT, integrasi Passport, dan otorisasi berbasis role. Kalian akan belajar melindungi endpoint agar hanya bisa diakses pengguna yang terautentikasi dengan peran yang tepat.
Sebelum masuk kode, pahami prinsip keamanan yang mendasarinya:
NestJS memberi struktur yang rapi untuk menerapkan semua prinsip ini lewat guards dan strategy.
npm install bcrypt @nestjs/jwtimport * as bcrypt from "bcrypt";
export async function hashPassword(password: string): Promise<string> {
const salt = await bcrypt.genSalt(10);
return bcrypt.hash(password, salt);
}bcrypt.hash menghasilkan hash yang aman dengan salt acak — install dulu dengan npm install bcrypt @nestjs/jwt. Jangan pernah menyimpan password mentah di database.
JSON Web Token (JWT) adalah token yang membawa klaim terenkripsi — biasanya identitas user dan waktu kedaluwarsa. Token ini ditandatangani server sehingga bisa diverifikasi tanpa menyimpan session di server.
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async login(user: { id: number; username: string }): Promise<{ accessToken: string }> {
const payload = { sub: user.id, username: user.username };
return {
accessToken: await this.jwtService.signAsync(payload),
};
}
}signAsync membuat token yang berisi payload user. Token ini dikirim klien dan dipakai pada request berikutnya.
Guard menentukan apakah request boleh dilanjutkan. Guard autentikasi memeriksa token pada request, sedangkan guard otorisasi memeriksa peran pengguna.
Guard membaca token dari header Authorization, memverifikasinya dengan JwtService, lalu menyimpan payload ke request.user:
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private readonly jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>();
const auth = request.headers.authorization;
const token = auth?.startsWith("Bearer ") ? auth.split(" ")[1] : undefined;
if (!token) {
throw new UnauthorizedException("Token tidak ditemukan");
}
try {
request.user = await this.jwtService.verifyAsync(token);
} catch {
throw new UnauthorizedException("Token tidak valid");
}
return true;
}
}Guard memvalidasi token dari header Authorization dan menyimpan payload ke request.user.
NestJS juga mendukung Passport — library autentikasi populer. Dengan @nestjs/passport dan passport-jwt:
npm install @nestjs/passport passport passport-jwt
npm install -D @types/passport-jwt@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET ?? "rahasia",
});
}
async validate(payload: { sub: number; username: string }) {
return { userId: payload.sub, username: payload.username };
}
}Untuk membatasi akses per peran, buat decorator kustom bersama guard pembacanya:
export const ROLES_KEY = "roles";
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private readonly reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true;
}
const { user } = context.switchToHttp().getRequest();
return requiredRoles.some((role) => user.roles?.includes(role));
}
}@Controller("admin")
@UseGuards(RolesGuard)
export class AdminController {
@Get("reports")
@Roles("admin")
getReports(): string {
return "Laporan rahasia";
}
}Episode 12 membangun fondasi keamanan yang solid. Inti yang harus dibawa pulang:
request.user.@Roles dan RolesGuard menerapkan otorisasi berbasis peran.Reflector untuk membaca metadata dekorator.