Nuxt Security Hooks
Available hooks
Nuxt Security provides two custom hooks:
- The routeRules hook (Nitro runtime hook): to modify the settings of Nuxt-Security at runtime.
- The prerenderedHeaders hook (Nuxt buildtime hook): to create a headers configuration file for your static server.
Route Rules Hook
The nuxt-security:routeRules
hook is convenient when you don't know the applicable security options at build time.
This happens most frequently in the following cases:
- Your Nuxt application is designed to be deployed on multiple websites, with a different configuration for each website.
- Your security options are kept in a third-party vault system (e.g. Google Secret Manager), and your build system does not have access to the secrets.
nuxt-security:routeRules
hook will be invoked each time your server is restarted.How to use
In order to use this hook, you will need to write a Nitro plugin
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('nuxt-security:routeRules', (appSecurityOptions) => {
// Your code here
})
})
- The
appSecurityOptions
variable contains all your application security options in the form of router definitions.
These router definitions are provided in the form of h3's radix router rules. Please see radix3 for further details. - The anonymous function
(appSecurityOptions) => {}
will be called asynchronously
If you need to fetch your security data from an external secrets' manager API, you can useasync/await
in your code. - Your code can modify any security option inside this hook
For each route, you can modify the rules exactly as you would do it with therouteRules
option ofnuxt.config.ts
.
Examples
You can apply custom settings to your whole application by modifying the base /**
route :
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('nuxt-security:routeRules', async(appSecurityOptions) => {
const cspConnectSrc = await $fetch('https://secret-manager-api.com/api-route')
// This example replaces only the connect-src CSP directive
appSecurityOptions['/**'] = defuReplaceArray(
{
headers: {
contentSecurityPolicy: {
"connect-src": [cspConnectSrc]
}
}
},
appSecurityOptions['/**']
)
})
})
You can also apply your settings to selected sub-routes of your application :
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('nuxt-security:routeRules', async(appSecurityOptions) => {
const cspConnectSrc = await $fetch('https://secret-manager-api.com/api-route')
// This example modifies the CSP only for `/admin/**` routes
appSecurityOptions['/admin/**'] = defuReplaceArray(
{
headers: {
contentSecurityPolicy: {
"connect-src": [cspConnectSrc]
}
}
},
appSecurityOptions['/admin/**']
)
})
})
You are not constrained to CSP options, you can modify any security option with this hook :
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('nuxt-security:routeRules', async(appSecurityOptions) => {
const tokenLimit = await $fetch('https://secret-manager-api.com/api-route')
// This example modifies the Rate Limiter only for API routes
// It also modifies the X-Powered-By setting for these routes
appSecurityOptions['/api/**'] = defuReplaceArray(
{
rateLimiter: {
tokensPerInterval: tokenLimit
},
hidePoweredBy: false
},
appSecurityOptions['/api/**']
)
})
})
Prerendered Headers Hook
The nuxt-security:prerenderedHeaders
hook is convenient when you want to know the security headers that should be delivered by your static server.
This happens most frequently when you deploy your website statically on a CDN. In that case, your server has the HTML pages, but it doesn't know which security headers should be delivered.
You may want to configure your hosting provider so that the correct headers are delivered for each static page.
nuxt-security:prerenderedHeaders
hook will be invoked each time your build your application.How to use
In order to use this hook, you will need write your code in defineNuxtConfig
export default defineNuxtConfig({
hooks: {
'nuxt-security:prerenderedHeaders': (prerenderedHeaders) => {
// Your code here
}
}
})
- The
prerenderedHeaders
variable contains all calculated headers for each page.{ '/page1': { header1: value1, header2: value2 }, '/page2': { header3: value3, ... } }
- The anonymous function
(prerenderedHeaders) => {}
will be called asynchronously
If you need to write to files asynchronously in your code, you can useasync/await
in your code.
Examples
You can generate nginx-compatible header rules within your CI/CD pipeline and save them to a file on disk :
import { writeFile } from 'node:fs/promises'
defineNuxtConfig({
hooks: {
'nuxt-security:prerenderedHeaders': async(prerenderedHeaders) => {
// Don't take this snippet for granted, this is just provided as a basic example
let nginxText = ''
for (const path in prerenderedHeaders) {
nginxText += 'location ' + path + ' {\n'
const headersForPath = prerenderedHeaders[path]
for (const headerName in headersForPath) {
const headerValue = headersForPath[headerName]
nginxText += ` add_header ${headerName} "${headerValue}";\n`
}
nginxText += '}\n\n'
}
await writeFile('./.nuxt/server.headers', nginxText)
}
}
})