Thanks to visit codestin.com
Credit goes to github.com

Skip to content

josegarridodigio/nestjs-guards

Repository files navigation

πŸ›‘οΈ NestJS Guards Demo - Educational Security Examples

A comprehensive educational project demonstrating authentication, authorization, and security guards in NestJS. This project showcases best practices for implementing various security patterns using JWT tokens, role-based access control (RBAC), and API key authentication.

🎯 Project Overview

This project serves as a complete reference for implementing security in NestJS applications, featuring:

  • JWT Authentication with login/logout functionality
  • Role-based Authorization (RBAC) with multiple user roles
  • API Key Authentication for service-to-service communication
  • Custom Security Guards with detailed implementations
  • Parameter Decorators for clean, reusable code
  • Comprehensive Swagger Documentation for all endpoints
  • Educational Comments explaining every security concept

✨ Features

πŸ” Authentication & Authorization

  • βœ… JWT-based authentication with secure token handling
  • βœ… Role-based access control (User, Admin, Moderator)
  • βœ… API key authentication for external services
  • βœ… Public endpoint exemptions with @Public() decorator
  • βœ… Custom parameter decorators (@CurrentUser(), @Roles())

πŸ›‘οΈ Security Guards Implemented

  • βœ… JwtAuthGuard - JWT token validation
  • βœ… RolesGuard - Role-based authorization
  • βœ… ApiKeyGuard - API key validation

οΏ½ Documentation & Developer Experience

  • βœ… Complete Swagger/OpenAPI documentation
  • βœ… Interactive API testing interface
  • βœ… Detailed code comments and examples
  • βœ… TypeScript type safety throughout
  • βœ… Educational README with examples

πŸ—οΈ Project Structure

src/
β”œβ”€β”€ auth/                              # Authentication module
β”‚   β”œβ”€β”€ decorators/                    # Custom decorators
β”‚   β”‚   β”œβ”€β”€ current-user.decorator.ts  # Extract current user from JWT
β”‚   β”‚   β”œβ”€β”€ public.decorator.ts        # Mark endpoints as public
β”‚   β”‚   └── roles.decorator.ts         # Define required roles
β”‚   β”œβ”€β”€ guards/                        # Security guards
β”‚   β”‚   β”œβ”€β”€ jwt-auth.guard.ts          # JWT authentication
β”‚   β”‚   β”œβ”€β”€ roles.guard.ts             # Role-based authorization
β”‚   β”‚   └── api-key.guard.ts           # API key validation
β”‚   β”œβ”€β”€ dto/                           # Data transfer objects
β”‚   β”‚   └── auth.dto.ts                # Login, response DTOs
β”‚   β”œβ”€β”€ interfaces/                    # TypeScript interfaces
β”‚   β”‚   └── auth.interface.ts          # JWT payload, user types
β”‚   β”œβ”€β”€ auth.controller.ts             # Authentication endpoints
β”‚   β”œβ”€β”€ auth.service.ts                # Authentication logic
β”‚   β”œβ”€β”€ auth.module.ts                 # Auth module configuration
β”‚   └── constants.ts                   # Role definitions, secrets
β”œβ”€β”€ users/                             # User management module
β”‚   β”œβ”€β”€ interfaces/                    # User-related interfaces
β”‚   β”œβ”€β”€ users.controller.ts            # User endpoints
β”‚   β”œβ”€β”€ users.service.ts               # User business logic
β”‚   └── users.module.ts                # Users module configuration
β”œβ”€β”€ app.controller.ts                  # Main application endpoints
β”œβ”€β”€ app.service.ts                     # Main application service
β”œβ”€β”€ app.module.ts                      # Root application module
└── main.ts                            # Application bootstrap + Swagger setup

πŸš€ Getting Started

Prerequisites

  • Node.js (v18 or higher)
  • pnpm (recommended) or npm

Installation

  1. Clone the repository:

    git clone <repository-url>
    cd nestjs-guards
  2. Install dependencies:

    pnpm install
  3. Configure environment variables:

    # Copy the environment template
    cp .env.example .env
    
    # Edit the .env file with your values
    nano .env  # or use your preferred editor

    Required variables:

    JWT_SECRET=your-super-secret-jwt-key-here
    JWT_EXPIRES_IN=1h
    API_KEY=your-api-key-here

    ⚠️ Security Note: Use strong, randomly generated secrets in production. See ENVIRONMENT_CONFIG.md for detailed configuration guide.

  4. Start the development server:

    pnpm run start:dev
  5. Access the application:

    • API Base URL: http://localhost:3000
    • Swagger Documentation: http://localhost:3000/api
    • API JSON Schema: http://localhost:3000/api-json

πŸ‘₯ Demo Users & Authentication

Demo User Accounts

Username Password Roles Description
admin admin123 admin Administrator
moderator mod123 moderator Content moderator
user user123 user Regular user

API Keys

Available demo API keys for testing:

  • demo-api-key-123
  • another-valid-key-456
  • test-key-789

πŸ“‹ API Endpoints Reference

Public Endpoints

Method Endpoint Description Authentication
GET / Welcome message None
GET /info API information None
POST /auth/login User login None
GET /auth/health Health check None
GET /users List all users None

JWT Protected Endpoints

Method Endpoint Description Required Role
GET /welcome Personalized welcome Any authenticated user
GET /auth/profile User profile Any authenticated user
GET /users/me Current user profile Any authenticated user
POST /auth/refresh Refresh JWT token Any authenticated user

Role-Based Endpoints

Method Endpoint Description Required Role
GET /auth/admin Admin-only data admin
GET /auth/moderate Moderation data admin or moderator
GET /users/:id User by ID admin
GET /users/stats/overview User statistics admin or moderator

API Key Protected Endpoints

Method Endpoint Description Authentication
GET /auth/api-protected API key demo API Key required
GET /auth/double-protected Dual protection JWT + API Key

πŸ”§ Usage Examples

1. Login and Get JWT Token

curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "admin123"}'

Response:

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "userId": 1,
    "username": "admin",
    "roles": ["admin"],
    "createdAt": "2024-01-01T12:00:00.000Z"
  }
}

2. Access Protected Endpoint with JWT

curl -X GET http://localhost:3000/auth/profile \
  -H "Authorization: Bearer YOUR_JWT_TOKEN_HERE"

3. Access Admin-Only Endpoint

curl -X GET http://localhost:3000/auth/admin \
  -H "Authorization: Bearer ADMIN_JWT_TOKEN_HERE"

4. Use API Key Authentication

curl -X GET http://localhost:3000/auth/api-protected \
  -H "X-API-Key: demo-api-key-123"

5. Dual Protection (JWT + API Key)

curl -X GET http://localhost:3000/auth/double-protected \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "X-API-Key: demo-api-key-123"

πŸ›‘οΈ Security Guards Explained

1. JWT Authentication Guard (JwtAuthGuard)

Purpose: Validates JWT tokens and extracts user information.

Implementation:

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }

  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    
    if (isPublic) return true;
    return super.canActivate(context);
  }
}

Usage:

@UseGuards(JwtAuthGuard)
@Get('profile')
getUserProfile(@CurrentUser() user: JwtPayload) {
  return { user };
}

2. Roles Guard (RolesGuard)

Purpose: Implements role-based access control.

Implementation:

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<UserRole[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    
    if (!requiredRoles) return true;
    
    const { user } = context.switchToHttp().getRequest();
    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

Usage:

@Roles('admin', 'moderator')
@Get('admin-data')
@UseGuards(JwtAuthGuard, RolesGuard)
getAdminData() {
  return { message: 'Admin-only data' };
}

3. API Key Guard (ApiKeyGuard)

Purpose: Validates API keys from request headers.

Implementation:

@Injectable()
export class ApiKeyGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const apiKey = request.headers['x-api-key'];
    return VALID_API_KEYS.includes(apiKey);
  }
}

Usage:

@UseGuards(ApiKeyGuard)
@Get('api-protected')
getApiProtectedData() {
  return { message: 'API Key protected data' };
}

🎨 Custom Decorators

@Public() Decorator

Marks endpoints as publicly accessible, bypassing JWT authentication:

export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

Usage:

@Public()
@Get('public-endpoint')
getPublicData() {
  return { message: 'This is public!' };
}

@Roles() Decorator

Defines required roles for endpoint access:

export const ROLES_KEY = 'roles';
export const Roles = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles);

Usage:

@Roles('admin')
@Get('admin-only')
getAdminOnlyData() {
  return { message: 'Admin only!' };
}

@CurrentUser() Decorator

Extracts current user information from JWT payload:

export const CurrentUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext): JwtPayload => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);

Usage:

@Get('me')
getCurrentUser(@CurrentUser() user: JwtPayload) {
  return { user };
}

πŸ“Š Security Architecture

Guard Execution Order

  1. Global JWT Guard - Applied to all routes by default
  2. Public Decorator Check - Bypasses authentication if @Public()
  3. JWT Token Validation - Validates and decodes JWT tokens
  4. Roles Guard - Checks user roles against required roles
  5. API Key Guard - Validates API keys when required

Security Flow Diagram

Request β†’ JWT Guard β†’ Public Check β†’ Token Validation β†’ Roles Guard β†’ API Key Guard β†’ Route Handler
                ↓              ↓              ↓              ↓               ↓
             If @Public     Validate JWT   Check User     Validate API    Execute
             β†’ Skip Auth    β†’ Extract User   Roles          Key (if req.)   Endpoint

πŸ§ͺ Testing the Application

1. Using Swagger UI

  1. Navigate to http://localhost:3000/api
  2. Use the "Authorize" button to input JWT tokens
  3. Test endpoints interactively with provided examples

2. Using cURL

All the cURL examples are provided in the Usage Examples section above.

3. Authentication Flow Test

# 1. Login
TOKEN=$(curl -s -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "admin123"}' \
  | jq -r '.access_token')

# 2. Use token to access protected endpoint
curl -X GET http://localhost:3000/auth/profile \
  -H "Authorization: Bearer $TOKEN"

πŸ”§ Configuration

Environment Variables

Create a .env file in the root directory:

# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key
JWT_EXPIRES_IN=24h

# API Keys
VALID_API_KEYS=demo-api-key-123,another-valid-key-456,test-key-789

# Application
PORT=3000
NODE_ENV=development

JWT Configuration

Located in src/auth/constants.ts:

/**
 * JWT Configuration Factory
 *
 * This function creates JWT configuration using environment variables.
 * Environment variables should be defined in .env file:
 * - JWT_SECRET: Secret key for signing JWT tokens
 * - JWT_EXPIRES_IN: Token expiration time (default: '1h')
 */
export const createJwtConfig = (configService: ConfigService) => ({
  secret:
    configService.get<string>('JWT_SECRET') ||
    'default-secret-change-in-production',
  expiresIn: configService.get<string>('JWT_EXPIRES_IN') || '1h',
});

Why use ConfigService?

  • βœ… Type Safety: Proper TypeScript support for configuration values
  • βœ… Environment Management: Better handling of different environments (dev, prod, test)
  • βœ… Validation: Built-in validation for configuration values
  • βœ… Dependency Injection: Integrates seamlessly with NestJS DI system
  • βœ… Testability: Easier to mock configuration in tests

πŸ“š Learning Resources

Key Concepts Demonstrated

  1. Guard Implementation - How to create and use custom guards
  2. Decorator Composition - Building reusable parameter decorators
  3. Role-Based Access Control - Implementing RBAC in NestJS
  4. JWT Handling - Secure token management and validation
  5. API Documentation - Comprehensive Swagger setup
  6. Security Best Practices - Proper authentication flows

Related NestJS Documentation

🀝 Contributing

This is an educational project. Contributions that improve the learning experience are welcome:

  1. Fork the repository
  2. Create a feature branch
  3. Add your improvements with detailed comments
  4. Ensure all examples are working
  5. Submit a pull request

πŸ“ License

This project is for educational purposes. Feel free to use it as a reference for learning NestJS security patterns.

🏷️ Tags

nestjs guards authentication authorization jwt rbac api-key security typescript swagger educational


Happy Learning! πŸŽ“

This project demonstrates production-ready security patterns in NestJS. Use it as a foundation for building secure, scalable applications with proper authentication and authorization.

πŸ“ Project Structure

src/
β”œβ”€β”€ auth/                     # Authentication module
β”‚   β”œβ”€β”€ decorators/          
β”‚   β”‚   β”œβ”€β”€ current-user.decorator.ts  # Extract user from request
β”‚   β”‚   β”œβ”€β”€ public.decorator.ts        # Mark routes as public
β”‚   β”‚   └── roles.decorator.ts         # Define required roles
β”‚   β”œβ”€β”€ guards/              
β”‚   β”‚   β”œβ”€β”€ jwt-auth.guard.ts          # JWT authentication
β”‚   β”‚   β”œβ”€β”€ roles.guard.ts             # Role-based authorization
β”‚   β”‚   └── api-key.guard.ts           # API key validation
β”‚   β”œβ”€β”€ interfaces/          
β”‚   β”‚   └── auth.interface.ts          # TypeScript interfaces
β”‚   β”œβ”€β”€ auth.controller.ts             # Auth endpoints
β”‚   β”œβ”€β”€ auth.service.ts                # Auth business logic
β”‚   β”œβ”€β”€ auth.module.ts                 # Auth module configuration
β”‚   └── constants.ts                   # JWT config & user roles
β”œβ”€β”€ users/                    # User management module
β”‚   β”œβ”€β”€ interfaces/          
β”‚   β”‚   └── user.interface.ts          # User entity interface
β”‚   β”œβ”€β”€ users.controller.ts            # User endpoints
β”‚   β”œβ”€β”€ users.service.ts               # User business logic
β”‚   └── users.module.ts                # User module configuration
β”œβ”€β”€ app.controller.ts                  # Main app routes
β”œβ”€β”€ app.service.ts                     # Main app service
β”œβ”€β”€ app.module.ts                      # Root module
└── main.ts                           # Application entry point

πŸš€ Installation

  1. Clone and install dependencies:
git clone <repository-url>
cd nestjs-guards
pnpm install
  1. Start the development server:
pnpm run start:dev
  1. The application will be available at:
http://localhost:3000

πŸƒβ€β™‚οΈ Running the Application

Development

pnpm run start:dev    # Watch mode
pnpm run start:debug  # Debug mode

Production

pnpm run build
pnpm run start:prod

Testing

pnpm run test         # Unit tests
pnpm run test:e2e     # End-to-end tests
pnpm run test:cov     # Coverage report

πŸ” Authentication & Authorization

Default Users

The application comes with pre-configured users for testing:

Username Password Roles Description
john changeme user Regular user
admin admin123 admin Administrator
moderator mod123 moderator, user Moderator

Demo API Keys

For API key authentication testing:

  • demo-api-key-123
  • another-valid-key-456
  • test-key-789

πŸ›£οΈ API Endpoints

Public Endpoints (No Authentication Required)

Method Endpoint Description
GET / Welcome message
GET /info API documentation
GET /auth/health Health check
POST /auth/login User login
GET /users List all users (public data)

JWT Protected Endpoints

Method Endpoint Description Required Role
GET /welcome Personalized welcome Any authenticated
GET /auth/profile Current user profile Any authenticated
GET /users/me Own user data Any authenticated
POST /auth/refresh Refresh JWT token Any authenticated

Role-Based Endpoints

Method Endpoint Description Required Role
GET /auth/admin Admin-only data admin
GET /auth/moderate Moderation data admin or moderator
GET /users/:id User by ID admin
GET /users/stats/overview User statistics admin or moderator

API Key Protected Endpoints

Method Endpoint Description Authentication
GET /auth/api-protected API key protected data API Key
GET /auth/double-protected Double protection JWT + API Key

πŸ›‘οΈ Guards Explained

1. JwtAuthGuard

Purpose: Validates JWT tokens and extracts user information.

Features:

  • Extracts Bearer tokens from Authorization header
  • Validates token signature and expiration
  • Supports public routes with @Public() decorator
  • Attaches user payload to request object

Usage:

@UseGuards(JwtAuthGuard)
@Get('protected')
getProtectedData(@CurrentUser() user: JwtPayload) {
  return { user };
}

2. RolesGuard

Purpose: Implements role-based access control.

Features:

  • Works with @Roles() decorator
  • Checks user roles against required roles
  • Supports multiple roles per route
  • Must be used after authentication guard

Usage:

@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin', 'moderator')
@Get('admin-data')
getAdminData() {
  return { message: 'Admin only' };
}

3. ApiKeyGuard

Purpose: Validates API keys for alternative authentication.

Features:

  • Supports X-API-Key header
  • Supports Authorization: ApiKey <key> format
  • Independent of JWT authentication
  • Configurable API key validation

Usage:

@UseGuards(ApiKeyGuard)
@Get('api-data')
getApiData() {
  return { message: 'API key protected' };
}

Global Guard Configuration

To enable global authentication (protect all routes by default):

// In auth.module.ts
providers: [
  {
    provide: APP_GUARD,
    useClass: JwtAuthGuard,
  },
]

🏷️ Decorators

@Public()

Marks routes as public, bypassing global authentication.

@Public()
@Get('public-info')
getPublicInfo() {
  return { info: 'This is public' };
}

@Roles(...roles)

Specifies required roles for route access.

@Roles('admin')
@Get('admin-only')
getAdminOnly() {
  return { data: 'Admin only' };
}

@CurrentUser()

Extracts authenticated user from request.

// Get full user object
@Get('profile')
getProfile(@CurrentUser() user: JwtPayload) {
  return user;
}

// Extract specific property
@Get('username')
getUsername(@CurrentUser('username') username: string) {
  return { username };
}

πŸ“ Usage Examples

1. Login and Get Token

# Login
curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "john", "password": "changeme"}'

# Response
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "userId": 1,
    "username": "john",
    "email": "[email protected]",
    "roles": ["user"]
  }
}

2. Access Protected Route

# Use the token from login
curl -H "Authorization: Bearer <your-jwt-token>" \
  http://localhost:3000/auth/profile

3. Access Role-Protected Route

# Admin only route (use admin credentials)
curl -H "Authorization: Bearer <admin-jwt-token>" \
  http://localhost:3000/auth/admin

4. API Key Authentication

# Using X-API-Key header
curl -H "X-API-Key: demo-api-key-123" \
  http://localhost:3000/auth/api-protected

# Using Authorization header
curl -H "Authorization: ApiKey demo-api-key-123" \
  http://localhost:3000/auth/api-protected

5. Multiple Guards

# Requires both JWT and API key
curl -H "Authorization: Bearer <jwt-token>" \
     -H "X-API-Key: demo-api-key-123" \
     http://localhost:3000/auth/double-protected

πŸ§ͺ Testing

Unit Tests

pnpm run test

E2E Tests

pnpm run test:e2e

Manual Testing

Use the provided curl commands to test all endpoints.

πŸ”’ Security Best Practices

1. JWT Security

  • βœ… Use strong, random secrets
  • βœ… Set appropriate token expiration
  • βœ… Implement token refresh mechanism
  • βœ… Validate tokens on every request

2. Password Security

  • βœ… Hash passwords with bcrypt
  • βœ… Use salt rounds (10+ recommended)
  • βœ… Never store plain text passwords
  • βœ… Remove passwords from API responses

3. Guard Implementation

  • βœ… Always validate input data
  • βœ… Handle errors gracefully
  • βœ… Use proper HTTP status codes
  • βœ… Log security events

4. Production Considerations

  • ⚠️ Store secrets in environment variables
  • ⚠️ Use HTTPS in production
  • ⚠️ Implement rate limiting
  • ⚠️ Add request logging
  • ⚠️ Use proper CORS configuration

πŸ“š Learning Resources

Official Documentation

Key Concepts Covered

  • Guards: Route protection and access control
  • Decorators: Metadata and parameter extraction
  • JWT: Token-based authentication
  • RBAC: Role-based authorization
  • Middleware vs Guards: Understanding the differences

Advanced Topics

  • Custom guard implementation
  • Guard composition strategies
  • Global vs route-level protection
  • Multiple authentication methods
  • Error handling in guards

🀝 Contributing

This is an educational project. Contributions that improve the learning experience are welcome:

  1. Fork the repository
  2. Create a feature branch
  3. Add comprehensive comments to your code
  4. Update documentation if needed
  5. Create a pull request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

🎯 Next Steps

After exploring this demo, consider:

  1. Database Integration: Replace mock data with real database
  2. Refresh Tokens: Implement proper refresh token strategy
  3. Rate Limiting: Add request rate limiting
  4. Email Verification: Add email confirmation flow
  5. Password Reset: Implement password reset functionality
  6. OAuth Integration: Add third-party authentication
  7. Audit Logging: Track authentication events

Happy Learning! πŸš€

This project demonstrates production-ready patterns for authentication and authorization in NestJS. Use it as a foundation for your own applications and as a reference for implementing security in enterprise applications.

About

πŸ›‘οΈ NestJS Guards Demo - Educational Security Examples

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published