Advanced

Nuxt Security Hooks

Use hooks to further customize Nuxt Security

Available hooks

Nuxt Security provides two custom hooks:

  1. The routeRules hook (Nitro runtime hook): to modify the settings of Nuxt-Security at runtime.
  2. 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.
Your 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

/server/plugins/my-plugin.ts
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 use async/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 the routeRules option of nuxt.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.

Your 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

nuxt.config.ts
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 use async/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 :

nuxt.config.ts
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)
    }
  }
})