1.0.8 • Published 5 months ago

@develop-x/nest-internal-auth v1.0.8

Weekly downloads
-
License
-
Repository
-
Last release
5 months ago

@develop-x/nest-internal-auth

Overview

@develop-x/nest-internal-auth is a NestJS package that provides internal API authentication middleware for microservices communication. It validates API keys to ensure secure service-to-service communication within your infrastructure.

Installation

npm install @develop-x/nest-internal-auth

Features

  • API Key Authentication: Secure internal service communication with API keys
  • Middleware Integration: Easy integration with NestJS middleware system
  • Environment Variable Support: Configurable through environment variables
  • Unauthorized Exception Handling: Automatic rejection of invalid requests
  • Header Flexibility: Supports multiple header formats for API keys

Usage

Module Import

Import the InternalAuthModule in your application module:

import { Module } from '@nestjs/common';
import { InternalAuthModule } from '@develop-x/nest-internal-auth';

@Module({
  imports: [InternalAuthModule],
  // ... other module configuration
})
export class AppModule {}

Environment Configuration

Set the internal API key in your environment variables:

# .env file
INTERNAL_API_KEY=your-secret-api-key-here

Applying Middleware

Global Application

Apply the middleware globally to protect all routes:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { InternalAuthMiddleware } from '@develop-x/nest-internal-auth';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  // Apply middleware globally
  app.use(new InternalAuthMiddleware().use);
  
  await app.listen(3000);
}
bootstrap();

Specific Routes

Apply the middleware to specific routes or controllers:

import { Module, MiddlewareConsumer, RequestMethod } from '@nestjs/common';
import { InternalAuthMiddleware } from '@develop-x/nest-internal-auth';

@Module({
  // ... module configuration
})
export class AppModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(InternalAuthMiddleware)
      .forRoutes(
        { path: '/internal/*', method: RequestMethod.ALL },
        { path: '/admin/*', method: RequestMethod.ALL }
      );
  }
}

Controller Level

Apply the middleware at the controller level:

import { Controller, Get, UseGuards } from '@nestjs/common';
import { InternalAuthMiddleware } from '@develop-x/nest-internal-auth';

@Controller('internal')
export class InternalController {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(InternalAuthMiddleware)
      .forRoutes(InternalController);
  }

  @Get('health')
  getHealth() {
    return { status: 'ok' };
  }
}

API Reference

InternalAuthMiddleware

The main middleware class that validates API keys.

Headers

The middleware accepts API keys in the following headers:

  • x-api-key (lowercase)
  • X-API-KEY (uppercase)

Authentication Flow

  1. Extract API key from request headers
  2. Compare with INTERNAL_API_KEY environment variable
  3. Allow request if keys match
  4. Throw UnauthorizedException if keys don't match or are missing

Client Usage

Making Authenticated Requests

When calling internal APIs, include the API key in the request headers:

// Using axios
import axios from 'axios';

const response = await axios.get('http://internal-service/api/data', {
  headers: {
    'x-api-key': process.env.INTERNAL_API_KEY
  }
});

// Using fetch
const response = await fetch('http://internal-service/api/data', {
  headers: {
    'X-API-KEY': process.env.INTERNAL_API_KEY
  }
});

// Using NestJS HttpService
import { HttpService } from '@nestjs/axios';

@Injectable()
export class ApiClient {
  constructor(private readonly httpService: HttpService) {}

  async getData() {
    return this.httpService.get('http://internal-service/api/data', {
      headers: {
        'x-api-key': process.env.INTERNAL_API_KEY
      }
    }).toPromise();
  }
}

Security Considerations

API Key Management

  1. Environment Variables: Store API keys in environment variables, never in code
  2. Key Rotation: Regularly rotate API keys for better security
  3. Unique Keys: Use different API keys for different environments (dev, staging, prod)
  4. Strong Keys: Generate cryptographically strong API keys

Best Practices

// Good: Using environment variables
const apiKey = process.env.INTERNAL_API_KEY;

// Bad: Hardcoded API key
const apiKey = 'hardcoded-api-key-123';

Key Generation

Generate secure API keys using cryptographic libraries:

# Using openssl
openssl rand -hex 32

# Using Node.js crypto
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Error Handling

Unauthorized Responses

When authentication fails, the middleware throws an UnauthorizedException:

{
  "statusCode": 401,
  "message": "Invalid internal API key",
  "error": "Unauthorized"
}

Custom Error Handling

You can create custom exception filters to handle authentication errors:

import { ExceptionFilter, Catch, ArgumentsHost, UnauthorizedException } from '@nestjs/common';
import { Response } from 'express';

@Catch(UnauthorizedException)
export class AuthExceptionFilter implements ExceptionFilter {
  catch(exception: UnauthorizedException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();

    response.status(401).json({
      error: 'Authentication Failed',
      message: 'Invalid or missing internal API key',
      timestamp: new Date().toISOString()
    });
  }
}

Integration Examples

With Service Discovery

import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConsulService } from '@develop-x/nest-consul';

@Injectable()
export class InternalApiClient {
  constructor(
    private readonly httpService: HttpService,
    private readonly consulService: ConsulService
  ) {}

  async callInternalService(serviceName: string, endpoint: string) {
    const serviceUrl = await this.consulService.getServiceUrl(serviceName);
    
    return this.httpService.get(`${serviceUrl}${endpoint}`, {
      headers: {
        'x-api-key': process.env.INTERNAL_API_KEY
      }
    }).toPromise();
  }
}

With Circuit Breaker

import { Injectable } from '@nestjs/common';
import { HttpClientService } from '@develop-x/nest-service-connector';

@Injectable()
export class ResilientApiClient {
  constructor(private readonly httpClient: HttpClientService) {}

  async callWithCircuitBreaker(serviceName: string, endpoint: string) {
    return this.httpClient
      .createRequest(serviceName)
      .setPath(endpoint)
      .setHeaders({
        'x-api-key': process.env.INTERNAL_API_KEY
      })
      .get();
  }
}

Testing

Unit Testing

import { Test, TestingModule } from '@nestjs/testing';
import { UnauthorizedException } from '@nestjs/common';
import { InternalAuthMiddleware } from '@develop-x/nest-internal-auth';

describe('InternalAuthMiddleware', () => {
  let middleware: InternalAuthMiddleware;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [InternalAuthMiddleware],
    }).compile();

    middleware = module.get<InternalAuthMiddleware>(InternalAuthMiddleware);
  });

  it('should allow request with valid API key', () => {
    const req = {
      headers: { 'x-api-key': process.env.INTERNAL_API_KEY }
    };
    const res = {};
    const next = jest.fn();

    expect(() => middleware.use(req, res, next)).not.toThrow();
    expect(next).toHaveBeenCalled();
  });

  it('should reject request with invalid API key', () => {
    const req = {
      headers: { 'x-api-key': 'invalid-key' }
    };
    const res = {};
    const next = jest.fn();

    expect(() => middleware.use(req, res, next)).toThrow(UnauthorizedException);
  });
});

Dependencies

  • @nestjs/common: NestJS common utilities
  • express: Express.js types for request/response handling

License

ISC

Support

For issues and questions, please refer to the project repository or contact the development team.

1.0.8

5 months ago

1.0.7

5 months ago

1.0.6

5 months ago

1.0.5

5 months ago

1.0.4

5 months ago

1.0.3

5 months ago

1.0.2

5 months ago

1.0.1

5 months ago

1.0.0

5 months ago