npm package: @sicare/auth-guard
Description: A library for authentication and authorization in NestJS applications.
Latest version: 0.0.15

# @sicare/auth-guard

A customizable NestJS AuthGuard that authenticates requests by validating tokens via an external endpoint. Designed to work seamlessly with Fastify and Axios.

## ✨ Features

- 🔐 Token validation via a remote API.

- ✅ Easy integration with NestJS guards.

- 🌍 Supports global module registration.

- ⚠️ Throws proper NestJS HTTP exceptions based on the response.

## 📦 Installation

```bash
npm install @nestjs/axios @nestjs/microservices @sicare/auth-guard
```

Or using yarn:

```bash
yarn add @nestjs/axios @nestjs/microservices @sicare/auth-guard
```

## 🚧 Prerequisite: Use Fastify with NestJS

This package is built to work with FastifyAdapter in NestJS. Make sure your main app uses Fastify instead of the default Express:

### 1. Install Fastify

```bash
npm install fastify @nestjs/platform-fastify
```

Or using yarn:

```bash
yarn add fastify @nestjs/platform-fastify
```

### 2. Update main.ts

```typescript
import { NestFactory } from '@nestjs/core';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter(),
  );
  await app.listen(3000);
}
bootstrap();
```

## 🚀 Usage

### 1. Import the AuthGuardModule

In your main app or any feature module:

```typescript
import { Module } from '@nestjs/common';
import { AuthGuardModule } from '@sicare/auth-guard';

@Module({
  imports: [
    AuthGuardModule.register({
      endpoint: 'https://your-auth-service/validate',
      isGlobal: true, // Optional: make the guard global
    }),
  ],
})
export class AppModule {}
```

### 2. Apply the Guard

### 2.1. External Auth Guard

Use it in your controller or route handler:

```typescript
import { Controller, Get, UseGuards } from '@nestjs/common';
import { ExternalAuthGuard } from '@sicare/auth-guard';

@Controller('secure')
@UseGuards(ExternalAuthGuard)
export class SecureController {
  @Get()
  getData() {
    return { message: 'You are authenticated!' };
  }
}
```

### 2.2. Jwt Auth Guard

Config Jwks endpoint in AuthGuardModule register method.

```typescript
import { Module } from '@nestjs/common';
import { AuthGuardModule } from '@sicare/auth-guard';

@Module({
  imports: [
    AuthGuardModule.register({
      endpoint: 'https://example.auth0.com/.well-known/jwks.json',
      isGlobal: true, // Optional: make the guard global
    }),
  ],
})
export class AppModule {}
```

Use JwtAuthGuard in your controller or route handler:

```typescript
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '@sicare/auth-guard';

@Controller('secure')
@UseGuards(JwtAuthGuard)
export class SecureController {
  @Get()
  getData() {
    return { message: 'You are authenticated!' };
  }
}
```

## 🎯 Decorators

Once a guard is applied, you can inject user information directly into your controller method parameters using the provided decorators.

### `@User()`

Injects the full user object from the request into a method parameter. The user object is populated by the guard after successful authentication.

```typescript
import { Controller, Get, UseGuards } from '@nestjs/common';
import { ExternalAuthGuard, User } from '@sicare/auth-guard';

@Controller('secure')
@UseGuards(ExternalAuthGuard)
export class SecureController {
  @Get()
  getData(@User() user: unknown) {
    return { user };
  }
}
```

### `@UserId()`

Injects the user's UUID from the authenticated token. It resolves the ID by checking the following claims in order: `userId`, `sub`.

```typescript
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard, UserId } from '@sicare/auth-guard';

@Controller('secure')
@UseGuards(JwtAuthGuard)
export class SecureController {
  @Get()
  getProfile(@UserId() userId: string) {
    return { userId };
  }
}
```

### 🧪 Testing

A basic test is included to verify the guard is defined:

```typescript
describe('ExternalAuthGuard', () => {
  it('should be defined', () => {
    expect(new ExternalAuthGuard()).toBeDefined();
  });
});
```

### ⚙️ Options
| Option       | Type              | Default    | Description                                                                      |
|--------------|-------------------|------------|----------------------------------------------------------------------------------|
| `endpoint`   | `string`          | —          | The URL of the external auth service or JWKS endpoint.                           |
| `isGlobal`   | `boolean`         | `false`    | When `true`, registers the module globally so no per-module import is needed.    |
| `strategy`   | `'http' \| 'jwt'` | `'http'`   | Determines which guard strategy is used (`ExternalAuthGuard` or `JwtAuthGuard`). |
| `audience`   | `string`          | —          | *(JWT only)* Expected audience claim for JWT validation.                         |

### 🛡️ Behavior

- The guard reads the Authorization header.

- Sends the token to the configured endpoint via Axios.

- Injects the result as request.raw.user.

- Responds with:
  - `400 Bad Request` if the token is malformed.
  - `401 Unauthorized` if the token is missing or invalid.
  - `403 Forbidden` if the token is valid but the user is not authorized.
  - `404 Not Found` if the endpoint is not reachable.
  - `500 Internal Server Error` for any other errors.