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
    }
  })
})

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
      }
    }
  }
})

Overwriting or modifying existing values

Within your runtime hooks, you can either overwrite or modify the existing values for any security option. One of the easiest way to merge existing rules with your own is to use defu:

server/plugins/filename.ts
import defu from 'defu'

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'] = defu(
      { 
        headers: {
          contentSecurityPolicy: {
            "connect-src": ["'self'", validDomain]
          },
          xFrameOptions: false
        },
        hidePoweredBy: false
      },
      routeRules['/some/route']
    )
  })
})