thebushidocollective/han/nestjs-guards-interceptors

Claude Code and agent skill by thebushidocollective/han

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Use when nestJS guards and interceptors for auth, logging, and transformation. Use when implementing cross-cutting concerns.

Install

npx vskill@latest install thebushidocollective/han/nestjs-guards-interceptors

SKILL.md

NestJS Guards and Interceptors

Master NestJS guards and interceptors for implementing authentication, authorization, logging, and request/response transformation.

Guards Fundamentals

Understanding CanActivate and ExecutionContext.

typescript
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class BasicGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
const request = context.switchToHttp().getRequest();
return this.validateRequest(request);
}
private validateRequest(request: any): boolean {
// Simple validation logic
return !!request.headers.authorization;
}
}
// ExecutionContext provides context about current request
@Injectable()
export class ContextAwareGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
// Get HTTP context
const httpContext = context.switchToHttp();
const request = httpContext.getRequest();
const response = httpContext.getResponse();
// Get handler and class information
const handler = context.getHandler();
const controller = context.getClass();
console.log(`Handler: ${handler.name}`);
console.log(`Controller: ${controller.name}`);
return true;
}
}
// Usage in controller
import { Controller, Get, UseGuards } from '@nestjs/common';
@Controller('users')
@UseGuards(BasicGuard)
export class UserController {
@Get()
findAll() {
return [];
}
@Get('profile')
@UseGuards(ContextAwareGuard) // Method-level guard
getProfile() {
return { name: 'John' };
}
}

Authentication Guards

JWT, session, and API key authentication patterns.

typescript
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException('No token provided');
}
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: process.env.JWT_SECRET,
});
// Attach user to request
request['user'] = payload;
} catch {
throw new UnauthorizedException('Invalid token');
}
return true;
}
private extractTokenFromHeader(request: any): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
// Session-based authentication
@Injectable()
export class SessionAuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
if (!request.session || !request.session.userId) {
throw new UnauthorizedException('Not authenticated');
}
return true;
}
}
// API Key authentication
@Injectable()
export class ApiKeyGuard implements CanActivate {
constructor(private configService: ConfigService) {}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const apiKey = request.headers['x-api-key'];
if (!apiKey) {
throw new UnauthorizedException('API key required');
}
const validApiKey = this.configService.get('API_KEY');
if (apiKey !== validApiKey) {
throw new UnauthorizedException('Invalid API key');
}
return true;
}
}
// Multiple auth strategies
@Injectable()
export class MultiAuthGuard implements CanActivate {
constructor(
private jwtService: JwtService,
private configService: ConfigService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
// Try JWT first
const token = this.extractTokenFromHeader(request);
if (token) {
try {
const payload = await this.jwtService.verifyAsync(token);
request['user'] = payload;
return true;
} catch {}
}
// Fall back to API key
const apiKey = request.headers['x-api-key'];
if (apiKey === this.configService.get('API_KEY')) {
return true;
}
throw new UnauthorizedException();
}
private extractTokenFromHeader(request: any): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}

Role-Based Authorization Guards

RBAC patterns with decorators.

typescript
import { SetMetadata } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
// Define roles
export enum Role {
USER = 'user',
ADMIN = 'admin',
MODERATOR = 'moderator',
}
// Roles decorator
export const ROLES_KEY = 'roles';
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
// Roles guard
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) {
return true; // No roles required
}
const request = context.switchToHttp().getRequest();
const user = request.user;
if (!user) {
throw new UnauthorizedException('User not authenticated');
}
const hasRole = requiredRoles.some((role) => user.roles?.includes(role));
if (!hasRole) {
throw new ForbiddenException('Insufficient permissions');
}
return true;
}
}
// Usage
@Controller('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
export class AdminController {
@Get('users')
@Roles(Role.ADMIN)
getAllUsers() {
return [];
}
@Get('moderate')
@Roles(Role.ADMIN, Role.MODERATOR)
moderateContent() {
return { message: 'Moderation tools' };
}
}
// Permission-based authorization
export const PERMISSIONS_KEY = 'permissions';
export const RequirePermissions = (...permissions: string[]) =>
SetMetadata(PERMISSIONS_KEY, permissions);
@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
PERMISSIONS_KEY,
[context.getHandler(), context.getClass()],
);
if (!requiredPermissions) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
const hasPermission = requiredPermissions.every((permission) =>
user.permissions?.includes(permission),
);
if (!hasPermission) {
throw new ForbiddenException('Missing required permissions');
}
return true;
}
}
// Resource ownership guard
@Injectable()
export class ResourceOwnerGuard implements CanActivate {
constructor(private usersService: UsersService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const user = request.user;
const resourceId = request.params.id;
const resource = await this.usersService.findOne(resourceId);
if (!resource) {
throw new NotFoundException('Resource not found');
}
if (resource.userId !== user.id && !user.roles.includes(Role.ADMIN)) {
throw new ForbiddenException('You do not own this resource');
}
// Attach resource to request for later use
request['resource'] = resource;
return true;
}
}

Interceptors Fundamentals

NestInterceptor and response transformation.

typescript
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
// Basic interceptor
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
console.log('Before...');
const now = Date.now();
return next
.handle()
.pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
}
}
// Transform response
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
return next.handle().pipe(
map((data) => ({
data,
timestamp: new Date().toISOString(),
path: context.switchToHttp().getRequest().url,
})),
);
}
}
interface Response<T> {
data: T;
timestamp: string;
path: string;
}
// Error handling in interceptor
@Injectable()
export class ErrorsInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
catchError((err) => {
console.error('Error caught in interceptor:', err);
throw new InternalServerErrorException('Something went wrong');
}),
);
}
}
// Usage
@Controller('users')
@UseInterceptors(LoggingInterceptor)
export class UserController {
@Get()
@UseInterceptors(TransformInterceptor)
findAll() {
return [{ id: 1, name: 'John' }];
}
}

Logging Interceptors

Advanced logging patterns.

typescript
import { Logger } from '@nestjs/common';
@Injectable()
export class RequestLoggingInterceptor implements NestInterceptor {
private readonly logger = new Logger(RequestLoggingInterceptor.name);
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url, body } = request;
const userAgent = request.get('user-agent') || '';
this.logger.log(`Incoming Request: ${method} ${url}`);
this.logger.debug(`User Agent: ${userAgent}`);
this.logger.debug(`Body: ${JSON.stringify(body)}`);
const now = Date.now();
return next.handle().pipe(
tap({
next: (data) => {
const response = context.switchToHttp().getResponse();
this.logger.log(
`Response: ${method} ${url} ${response.statusCode} - ${Date.now() - now}ms`,
);
},
error: (err) => {
this.logger.error(
`Error: ${method} ${url} - ${err.message}`,
err.stack,
);
},
}),
);
}
}
// Performance monitoring
@Injectable()
export class PerformanceInterceptor implements NestInterceptor {
private readonly logger = new Logger(PerformanceInterceptor.name);
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const { method, url } = request;
const startTime = Date.now();
return next.handle().pipe(
tap(() => {
const duration = Date.now() - startTime;
if (duration > 1000) {
this.logger.warn(`Slow request: ${method} ${url} - ${duration}ms`);
} else {
this.logger.log(`${method} ${url} - ${duration}ms`);
}
}),
);
}
}

Response Transformation Interceptors

Shaping API responses consistently.

typescript
// Wrap all responses
@Injectable()
export class ResponseWrapperInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map((data) => {
const response = context.switchToHttp().getResponse();
return {
statusCode: response.statusCode,
message: 'Success',
data,
};
}),
);
}
}

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
198
Repository forks
21
7-day trend score
26

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 18 Mar 2026, 7 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/thebushidocollective/han/nestjs-guards-interceptors/badge)](https://verified-skill.com/skills/thebushidocollective/han/nestjs-guards-interceptors)

Something wrong with this skill or its page? Tell us.