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.
// 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.
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.
// 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.
// 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:
// 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: