Getting Started

Usage

Learn how to use headers and middleware both globally and per route.

Nuxt Security by default registers a set of global Nuxt routeRules that will make your application more secure by default. Both headers and middleware can be easily configured and even disabled when needed.

Read more about security headers here.

Global configuration

To override the default behavior for Nuxt Security globally, follow this pattern:

nuxt.config.ts
export default defineNuxtConfig({
  security: {
    headers: {
      // certain header
      xXSSProtection: '1',
    },

    // certain middleware
    rateLimiter: {
      // options
    }
  }
})

Per route configuration

To enable per-route configuration, use the routeRules like following:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/custom-route': {
      headers: {
        'Foo': 'Bar'
        /* DO NOT DEFINE SECURITY HEADERS HERE
        'Cross-Origin-Embedder-Policy': 'require-corp'
        */
      }

      security: {
        // INSTEAD USE THE CUSTOM NUXT-SECURITY PROPERTY
        headers: {
          // certain header
          crossOriginEmbedderPolicy: 'require-corp'
        },

        // certain middleware
        rateLimiter: {
          // options
        }
      }
    }
  }
})
When using routeRules, do not use the standard headers property to define Nuxt Security options.
Instead, make sure to use the security property. This is a custom NuxtSecurity addition that does not exists in core Nuxt.
If your application defines conflicting headers at both levels, the security property will take precedence.

For more information on routeRules please see the Nuxt documentation

Runtime hooks

If you need to change the configuration at runtime, it is possible to do it through the nuxt-security:routeRules hook.

In order to use the runtime hooks feature, you will need to create a Nitro plugin.

In the server/plugins directory, create a new file with the name of your choice:

server/plugins/filename.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
    // You can fetch configuration data asynchronously from an external source
    const validDomain = await $fetch('https://some-site.com/rules')
    // You can then override the security options of any route
    routeRules['/some/route'] = { 
      headers: {
        contentSecurityPolicy: {
          "connect-src": ["'self'", validDomain]
        },
        xFrameOptions: false
      },
      hidePoweredBy: false
    }
  })
})
Runtime-hook configuration only applies to headers delivered on HTML pages.
Headers delivered on other resources (e.g. images, js and css files, api routes etc.) are not modifiable via runtime hooks.

Configuration priority order

Nuxt-Security applies your rules in the following prority order:

  1. Default rules

Nuxt-Security default values. See here

  1. Inline module options
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    ['nuxt-security', { /* Inline Options */ }]
  ]
})
  1. Global module options
nuxt.config.ts
export default defineNuxtConfig({
  security: {
    // Global Options
  }
})
  1. Per-route options
nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/some-route': {
      security: {
        // Per-route Options
      }
    }
  }
})
  1. Runtime-hook options
server/plugins/filename.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('nuxt-security:routeRules', routeRules => {
    // Runtime Options
  })
})

Route merging strategy (nested router)

If you define nested route rules in your routeRules definitions, Nuxt Security will recursively merge the options to resolve the security rules of a given route:

nuxt.config.ts
export default defineNuxtConfig({
  // Global
  security: {
    headers: {
      crossOriginEmbedderPolicy: 'require-corp' // By default, COEP is 'require-corp'
    }
  }
  // Per route
  routeRules: {
    '/some-prefix/**': {
      security: {
        headers: {
          crossOriginEmbedderPolicy: false // COEP disabled on all routes beginning with /some-prefix/
        }
      }
    },
    '/some-prefix/some-route': {
      security: {
        headers: {
          crossOriginEmbedderPolicy: 'credentialless' // COEP is 'credentialless' on /some-prefix/some-route
        }
      }
    }
  }
})

Inline route configuration

You can also use route roules in pages like following:

<template>
  <div>Hello from page</div>
</template>

<script setup lang="ts">
defineRouteRules({
  security: {
    headers: {
      xXSSProtection: '1'
    },
    rateLimiter: {
      tokensPerInterval: 3,
      interval: 60000,
    },
  }
})
</script>
To enable this macro, add the following configuration to your nuxt.config.ts file:
experimental: {
  inlineRouteRules: true
},

Disabling functionality

To disable certain middleware or headers, follow this pattern:

nuxt.config.ts
export default defineNuxtConfig({
  // global
  security: {
    headers: {
      // certain header
      contentSecurityPolicy: false
    },

    // certain middleware
    rateLimiter: false
  },

  // per route
  routeRules: {
    '/custom-route': {
      security: {
        rateLimiter: false
      }
    }
  }
})

Modifying security options

Within your runtime hooks, you can either modify or overwrite the existing values for any security option.

Merging with replacement

One of the easiest way to merge existing rules with your own is to use defuReplaceArray:

server/plugins/filename.ts
// You don't need to import defuReplaceArray as it is auto-imported by Nuxt Security

export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
    routeRules['/some/route'] = defuReplaceArray(
      { 
        headers: {
          contentSecurityPolicy: {
            "script-src": ["'self'", "..."]
            // The script-src directive will be replaced with "'self' ..."
          }
        }
      },
      routeRules['/some/route'] // The other existing rules for /some/route will be preserved
    )
  })
})

In the example above,

  • All existing security options for /some/route will be maintained, and only the script-src CSP directive will be modified.
  • The existing content of the script-src directive will be erased and replaced by your values

Read more about defuReplaceArray

defuReplaceArray is auto-imported by Nuxt Security. You can use this utility anywhere in your /server folder.

Merging with addition

If you want to add additional values to the existing settings, you can use the standard defu utility to merge your rules.

server/plugins/filename.ts
// You will need to import defu
import { defu } from 'defu'
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
    routeRules['/some/route'] = defu(
      { 
        headers: {
          contentSecurityPolicy: {
            "script-src": ["'self'", "..."]
            // The values "'self' ..." will be added to the existing values
          }
        }
      },
      routeRules['/some/route'] // The other existing rules for /some/route will be preserved
    )
  })
})

In the example above,

  • All existing security options for /some/route will be maintained, and only the script-src CSP directive will be modified.
  • The existing content of the script-src directive will be preserved, and your values will be added to the existing values.

Read more about defu

Overwriting rules

If you want to erase the existing settings, don't use defu and overwrite the values:

server/plugins/filename.ts
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('nuxt-security:routeRules', async(routeRules) => {
    routeRules['/some/route'] = { 
      headers: {
        contentSecurityPolicy: {
          "script-src": ["'self'", "..."]
        }
      }
    }
    // Any existing rules for /some/route will be erased
  })
})

In the example above,

  • All existing security options for /some/route will be erased.
  • The script-src directive will contain your values.