Skip to content
vv1.14.0
Main

Plugins & Agents System

The boilerplate introduces a Plugin/Agent System to handle cross-cutting concerns and feature extensions in a modular way. This allows you to "plug in" functionality like authentication, logging, or other middleware-like behaviors without cluttering the core request handling logic.

Concept

  • Agent: A category consisting of one or more plugins (e.g., authentication).
  • Plugin: A specific implementation of a strategy (e.g., JWT, OAuth).
  • Container: The context passed to plugins, containing the request state (headers, body, etc.).

Configuration

Plugins are configured in src/infrastructure/settings/plugins.ts. Each plugin can be toggled active and assigned a priority.

typescript
// src/infrastructure/settings/plugins.ts
import jwt from "@infrastructure/authentication/strategies/jwt";

export default {
    authentication: {
        JWT: {
            priority: 1,      // Lower numbers run first
            active: true,     // Enable/Disable
            strategy: jwt.session, // The function to execute
        },
    },
}

Request Flow

When a request is marked as restricted (requiring authentication/plugins), the system iterates through active plugins for the authentication agent, sorted by priority.

AuthenticateGet PluginsReturn DataSet SessionProceed/401

How to Add a New Authentication Plugin

O Boilerplate foi desenhado para aceitar N métodos de autenticação simultâneos sem poluir o Core do Fastify. A classe authentication.ts irá lidar com todas as estratégias registradas e injetar no request a primeira que retornar sucesso.

1. Define the Strategy

Create a function inside infrastructure/authentication/strategies/ that accepts the Fastify container and either returns the user payload or throws an error.

typescript
// src/infrastructure/authentication/strategies/api-key.ts
import type { container } from "@infrastructure/server/interface";

export async function verifyApiKey(request: container) {
	const key = request.headers()["x-api-key"];
	if (key === process.env.SECRET_API_KEY) {
		return { role: "admin", type: "api-key" };
	}
	throw new Error("Invalid or Missing API Key");
}

2. Register the Plugin

Injete a sua nova estratégia no "Ecosystem" passivo localizado em src/infrastructure/settings/plugins.ts. O campo name no objeto determina a chave que será acessível na sessão.

typescript
// src/infrastructure/settings/plugins.ts
import * as jwt from "@infrastructure/authentication/jwt";
import { verifyApiKey } from "@infrastructure/authentication/strategies/api-key";

export default {
	authentication: {
		// Existing JWT Strategy
		JWT: {
			priority: 2, 
			active: true,
			strategy: jwt.session,
		},
		// Your new Custom Strategy
		API_KEY: {
			priority: 1, // Will run BEFORE JWT (Lower number first)
			active: true, 
			strategy: verifyApiKey,
		}
	},
}

3. Accessing the Data

The authentication.ts module runs sorting by priority. If your API_KEY returns successfully, the request is instantly authenticated.

You can retrieve the result inside your Domain Actions via the .session() method:

typescript
// Inside any restricted action
export default async function myAction(request: container) {
   const sessionData = request.session();
   
   if (sessionData.API_KEY) {
	   console.log("Authenticated via API Key:", sessionData.API_KEY.role);
   } else if (sessionData.JWT) {
	   console.log("Authenticated via JWT Token:", sessionData.JWT.email);
   }
}

Middleware Sequence Flow

This is how the src/infrastructure/server/authentication.ts orchestrates the login passively:

x-api-keyTriggerPriority 1Priority 2Valid KeyInvalidValid TokenInvalid