### Complete AdonisJS Shield Configuration Source: https://context7.com/adonisjs/shield/llms.txt A production-ready Shield configuration example demonstrating all guards enabled and properly configured. This configuration can be adapted for different environments using environment variables. ```typescript // config/shield.ts import { defineConfig } from '@adonisjs/shield' const shieldConfig = defineConfig({ csp: { enabled: true, directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", '@nonce', 'https://cdn.jsdelivr.net'], styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], fontSrc: ["'self'", 'https://fonts.gstatic.com'], imgSrc: ["'self'", 'data:', 'https:'], connectSrc: ["'self'", process.env.API_URL!], frameSrc: ["'none'"], objectSrc: ["'none'"], baseUri: ["'self'"], formAction: ["'self'"], upgradeInsecureRequests: [], }, reportOnly: false, }, csrf: { enabled: true, exceptRoutes: [ '/api/webhooks/*', '/api/stripe/webhook', '/api/health', ], enableXsrfCookie: true, methods: ['POST', 'PUT', 'PATCH', 'DELETE'], cookieOptions: { sameSite: 'lax', secure: process.env.NODE_ENV === 'production', }, }, xFrame: { enabled: true, action: 'DENY', }, hsts: { enabled: process.env.NODE_ENV === 'production', maxAge: '1 year', includeSubDomains: true, preload: false, }, contentTypeSniffing: { enabled: true, }, }) export default shieldConfig ``` -------------------------------- ### Create HSTS Guard Source: https://context7.com/adonisjs/shield/llms.txt Use `hstsFactory` to create an HSTS guard. Configure the `maxAge`, `includeSubDomains`, and `preload` options to enforce HTTPS connections. Examples for production and development configurations are provided. ```typescript import { hstsFactory } from '@adonisjs/shield/guards' const hstsGuard = hstsFactory({ enabled: true, // Duration to remember HTTPS preference // Accepts string expressions: '1 year', '180 days', '6 months' // Or number in seconds: 31536000 maxAge: '1 year', // Apply HSTS to all subdomains includeSubDomains: true, // Enable HSTS preloading (browser built-in list) // Only enable after confirming HTTPS works for all subdomains preload: true, }) // Resulting header: // Strict-Transport-Security: max-age=31536000; includeSubDomains; preload // Production configuration example: const productionHsts = hstsFactory({ enabled: process.env.NODE_ENV === 'production', maxAge: '2 years', includeSubDomains: true, preload: true, }) // Development configuration (shorter duration for testing): const developmentHsts = hstsFactory({ enabled: true, maxAge: '1 hour', includeSubDomains: false, preload: false, }) ``` -------------------------------- ### Create Content Security Policy Guard Source: https://context7.com/adonisjs/shield/llms.txt Use `cspFactory` to create a CSP guard. Register custom keywords and define directives for various resource types like scripts, styles, and images. The `@nonce` keyword can be used to allow specific inline scripts. ```typescript import { cspFactory } from '@adonisjs/shield/guards' import { cspKeywords } from '@adonisjs/shield' // Register custom CSP keywords cspKeywords.register('@googleAnalytics', (req, res) => { return 'https://www.google-analytics.com' }) const cspGuard = cspFactory({ enabled: true, directives: { // Default policy for all resource types defaultSrc: ["'self'"], // Script sources - @nonce allows inline scripts with matching nonce scriptSrc: ["'self'", '@nonce', 'https://cdn.jsdelivr.net'], // Style sources styleSrc: ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'], // Font sources fontSrc: ["'self'", 'https://fonts.gstatic.com'], // Image sources imgSrc: ["'self'", 'data:', 'https:', 'blob:'], // API/fetch/XHR connections connectSrc: ["'self'", 'https://api.example.com', 'wss://socket.example.com'], // Frame sources (iframes) frameSrc: ["'self'", 'https://www.youtube.com'], // Object/embed/applet sources objectSrc: ["'none'"], // Form submission targets formAction: ["'self'"], // Base URI restriction baseUri: ["'self'"], // Upgrade insecure requests upgradeInsecureRequests: [], }, // Report-only mode (doesn't block, just reports violations) reportOnly: false, }) // In Edge.js templates, use the nonce for inline scripts: // // In a controller, access the nonce: // export default class PageController { // async show({ response, view }: HttpContext) { // const nonce = response.nonce // return view.render('page', { inlineScriptNonce: nonce }) // } // } ``` -------------------------------- ### Create Frame Guard Factory Source: https://context7.com/adonisjs/shield/llms.txt Use frameGuardFactory to create guards that set the X-Frame-Options header. Configure actions like DENY, SAMEORIGIN, or ALLOW-FROM with a specific domain. Conditional configuration based on environment variables is also supported. ```typescript import { frameGuardFactory } from '@adonisjs/shield/guards' // Deny all iframe embedding const denyFrameGuard = frameGuardFactory({ enabled: true, action: 'DENY', }) // Header: X-Frame-Options: DENY // Allow same-origin iframe embedding only const sameOriginGuard = frameGuardFactory({ enabled: true, action: 'SAMEORIGIN', }) // Header: X-Frame-Options: SAMEORIGIN // Allow embedding from a specific domain const allowFromGuard = frameGuardFactory({ enabled: true, action: 'ALLOW-FROM', domain: 'https://trusted-partner.com', }) // Header: X-Frame-Options: ALLOW-FROM https://trusted-partner.com // Conditional configuration based on environment const frameGuard = frameGuardFactory({ enabled: true, action: process.env.ALLOW_IFRAME_EMBED === 'true' ? 'SAMEORIGIN' : 'DENY', }) ``` -------------------------------- ### Configure @adonisjs/shield with defineConfig Source: https://context7.com/adonisjs/shield/llms.txt Use `defineConfig` to create a Shield configuration object, merging partial options with defaults. All guards are disabled by default, requiring explicit enabling. ```typescript import { defineConfig } from '@adonisjs/shield' const shieldConfig = defineConfig({ // Enable CSRF protection for form submissions csrf: { enabled: true, exceptRoutes: ['/api/webhooks', '/api/stripe/webhook'], enableXsrfCookie: true, methods: ['POST', 'PUT', 'PATCH', 'DELETE'], cookieOptions: { httpOnly: false, sameSite: 'strict', }, }, // Configure Content Security Policy csp: { enabled: true, directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", '@nonce', 'https://cdn.example.com'], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", 'data:', 'https:'], connectSrc: ["'self'", 'https://api.example.com'], }, reportOnly: false, }, // Enforce HTTPS connections hsts: { enabled: true, maxAge: '1 year', includeSubDomains: true, preload: true, }, // Prevent clickjacking attacks xFrame: { enabled: true, action: 'SAMEORIGIN', }, // Prevent MIME type sniffing contentTypeSniffing: { enabled: true, }, }) export default shieldConfig ``` -------------------------------- ### Configure Shield API Client Plugin Source: https://context7.com/adonisjs/shield/llms.txt Integrate the shieldApiClient plugin with Japa for testing CSRF protection. Ensure both apiClient and shieldApiClient are included in the configure function. ```typescript // tests/bootstrap.ts import { shieldApiClient } from '@adonisjs/shield/plugins/api_client' import { apiClient } from '@japa/api-client' import { configure } from '@japa/runner' configure({ plugins: [ apiClient(), shieldApiClient(), ], }) ``` -------------------------------- ### Register and Use ShieldMiddleware in AdonisJS Source: https://context7.com/adonisjs/shield/llms.txt The `ShieldMiddleware` orchestrates security guards. It's typically registered automatically, but manual registration in `start/kernel.ts` is shown. The middleware adds CSRF tokens and CSP nonces to the request and response context. ```typescript import ShieldMiddleware from '@adonisjs/shield/shield_middleware' import router from '@adonisjs/core/services/router' // The middleware is automatically registered when configuring the package. // Manual registration in start/kernel.ts: router.use([ () => import('@adonisjs/shield/shield_middleware') ]) // The middleware adds these properties to the request/response: // ctx.request.csrfToken - The CSRF token for the current session // ctx.response.nonce - A cryptographic nonce for CSP inline scripts // In a controller: export default class FormController { async show({ request, view }: HttpContext) { // Access the CSRF token programmatically const token = request.csrfToken // Render view with CSRF protection return view.render('form', { csrfToken: token }) } async submit({ request, response }: HttpContext) { // CSRF validation happens automatically for POST/PUT/PATCH/DELETE const data = request.only(['email', 'password']) // Process form submission... return response.redirect('/dashboard') } } ``` -------------------------------- ### Register Custom CSP Keywords Source: https://context7.com/adonisjs/shield/llms.txt Register custom keywords for dynamic CSP directive values. These are typically registered in a preload file before shield configuration. The built-in '@nonce' keyword is automatically registered. ```typescript import { cspKeywords } from '@adonisjs/shield' // Register custom keywords before shield configuration // Typically in a preload file: start/shield.ts // Built-in @nonce keyword (registered automatically) // Resolves to 'nonce-' // Register a custom keyword for trusted CDN cspKeywords.register('@trustedCdn', (request, response) => { return 'https://cdn.trusted.com' }) // Dynamic keyword based on environment cspKeywords.register('@apiEndpoint', (request, response) => { return process.env.NODE_ENV === 'production' ? 'https://api.production.com' : 'https://api.staging.com' }) // Use custom keywords in CSP configuration import { defineConfig } from '@adonisjs/shield' export default defineConfig({ csp: { enabled: true, directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", '@nonce', '@trustedCdn'], connectSrc: ["'self'", '@apiEndpoint'], }, }, }) ``` -------------------------------- ### Create CSRF Protection Guard Source: https://context7.com/adonisjs/shield/llms.txt Use `csrfFactory` to create a CSRF guard. Configure routes to exclude, enable XSRF cookies for JavaScript frameworks, and specify HTTP methods requiring validation. The guard integrates with Edge.js templates for token generation and rendering. ```typescript import { csrfFactory } from '@adonisjs/shield/guards' import type { HttpContext } from '@adonisjs/core/http' // Configuration options const csrfGuard = csrfFactory({ enabled: true, // Routes to exclude from CSRF validation exceptRoutes: ['/api/webhooks', '/api/external/*'], // Or use a function for dynamic exclusion // exceptRoutes: (ctx: HttpContext) => { // return ctx.request.url().startsWith('/api/public') // }, // Enable XSRF cookie for JavaScript frameworks (Angular, Axios) enableXsrfCookie: true, // HTTP methods that require CSRF validation methods: ['POST', 'PUT', 'PATCH', 'DELETE'], // Cookie options for XSRF-TOKEN cookie cookieOptions: { sameSite: 'strict', secure: true, }, }, encryption, edge) // In Edge.js templates, these helpers are available: // {{ csrfToken }} - The raw CSRF token value // {{{ csrfField() }}} - Renders: // {{{ csrfMeta() }}} - Renders: // Example form template (resources/views/form.edge): //
// {{{ csrfField() }}} // // //
// For AJAX requests, include the token in headers: // JavaScript example: // fetch('/api/data', { // method: 'POST', // headers: { // 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content, // 'Content-Type': 'application/json', // }, // body: JSON.stringify(data), // }) ``` -------------------------------- ### Test API Endpoints with CSRF Protection Source: https://context7.com/adonisjs/shield/llms.txt Use the withCsrfToken() method on the API client to automatically include a valid CSRF token in requests. Test various HTTP methods (POST, PUT, DELETE) and verify responses, including failure cases for missing tokens. ```typescript // tests/functional/users.spec.ts import { test } from '@japa/runner' test.group('User Management', () => { test('create new user with CSRF protection', async ({ client }) => { // The withCsrfToken() method automatically generates // a valid CSRF token and includes it in the request const response = await client .post('/users') .withCsrfToken() .json({ email: 'user@example.com', password: 'securePassword123', name: 'John Doe', }) response.assertStatus(201) response.assertBodyContains({ email: 'user@example.com' }) }) test('update user profile', async ({ client }) => { const response = await client .put('/users/1') .withCsrfToken() .withSession({ userId: 1 }) // Combine with session if needed .json({ name: 'Jane Doe' }) response.assertStatus(200) }) test('delete user account', async ({ client }) => { const response = await client .delete('/users/1') .withCsrfToken() .withSession({ userId: 1 }) response.assertStatus(204) }) test('request without CSRF token fails', async ({ client }) => { const response = await client .post('/users') .json({ email: 'user@example.com' }) response.assertStatus(403) }) }) ``` -------------------------------- ### Handle E_BAD_CSRF_TOKEN Exception Source: https://context7.com/adonisjs/shield/llms.txt Customize the exception handler to manage E_BAD_CSRF_TOKEN errors. For API requests, return a JSON response with an appropriate status code and message. For HTML requests, the default behavior of redirecting back with a flash error is preserved. ```typescript import { errors } from '@adonisjs/shield' // The exception is thrown automatically when CSRF validation fails // You can catch and customize it in exception handler // app/exceptions/handler.ts import { ExceptionHandler, HttpContext } from '@adonisjs/core/http' export default class Handler extends ExceptionHandler { async handle(error: unknown, ctx: HttpContext) { // Custom handling for CSRF errors if (error instanceof errors.E_BAD_CSRF_TOKEN) { // For API requests, return JSON if (ctx.request.accepts(['html', 'json']) === 'json') { return ctx.response.status(403).json({ error: 'CSRF_TOKEN_INVALID', message: 'Your session has expired. Please refresh and try again.', }) } // For HTML requests, the default behavior redirects back with flash // error.handle() is called automatically } return super.handle(error, ctx) } } // The error includes i18n support. Add translation: // resources/lang/en/errors.json: // { // "E_BAD_CSRF_TOKEN": "Your session has expired. Please refresh the page and try again." // } ``` -------------------------------- ### Create No Sniff Factory Source: https://context7.com/adonisjs/shield/llms.txt The noSniffFactory creates a guard that sets the X-Content-Type-Options header to 'nosniff'. This prevents browsers from MIME-sniffing responses, which can mitigate certain security risks. ```typescript import { noSniffFactory } from '@adonisjs/shield/guards' const noSniffGuard = noSniffFactory({ enabled: true, }) // Header: X-Content-Type-Options: nosniff // This prevents attacks where a browser might interpret a file // differently than the server intended, such as treating a // text file as executable JavaScript. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.