@fastify/cors

repository·main·Indexed 19 days ago

https://github.com/fastify/fastify-cors

A Fastify plugin that enables Cross-Origin Resource Sharing (CORS), allowing control over permitted origins, methods, and headers. It supports global configuration, per-route overrides via config.cors, and dynamic settings through asynchronous callbacks or delegator functions. The plugin automatically handles OPTIONS preflight requests and provides flexible origin validation using Booleans, Strings, RegExps, Arrays, or custom functions.

Tokens
2.9K
Snippets
10
Records
12
Agent score
17%

What's inside @fastify/cors

  1. Configure CORS asynchronously

    main

    If you need to determine CORS settings dynamically based on the request, you can configure CORS asynchronously. You can do this by passing a callback to fastify.register or by using the delegator key in the options object.

    // Method 1: Using a callback in register
    fastify.register(require('@fastify/cors'), (instance) => {
      return (req, callback) => {
        const corsOptions = {
          origin: true
        };
    
        if (/^localhost$/m.test(req.headers.origin)) {
          corsOptions.origin = false
        }
    
        callback(null, corsOptions)
      }
    })
    
    // Method 2: Using the delegator key in options
    fastify.register(require('@fastify/cors'), {
      hook: 'preHandler',
      delegator: (req, callback) => {
        const corsOptions = {
          origin: true
        };
    
        if (/^localhost$/m.test(req.headers.origin)) {
          corsOptions.origin = false
        }
    
        callback(null, corsOptions)
      },
    })
  2. Basic usage of @fastify/cors

    main

    To use @fastify/cors, import the plugin and register it with your Fastify instance. You can pass an options object or use the default settings.

    import Fastify from 'fastify'
    import cors from '@fastify/cors'
    
    const fastify = Fastify()
    await fastify.register(cors, {
      // put your options here
    })
    
    fastify.get('/', (req, reply) => {
      reply.send({ hello: 'world' })
    })
    
    await fastify.listen({ port: 3000 })
  3. Override CORS on a per-route basis

    main

    You can override the global CORS plugin options for specific routes using the config.cors property in the route definition.

    fastify.register(require('@fastify/cors'), { origin: 'https://example.com' })
    
    // Route with custom origin (Allow all)
    fastify.get('/cors-allow-all', {
      config: {
        cors: {
          origin: '*', 
        },
      },
    }, (_req, reply) => {
      reply.send('Custom CORS headers applied')
    })
    
    // Route with CORS disabled
    fastify.get('/cors-disabled', {
      config: {
        cors: false,
      },
    }, (_req, reply) => {
      reply.send('No CORS headers')
    })
  4. Configure the origin option

    main

    The origin option configures the Access-Control-Allow-Origin header.

    Warning: Using RegExp or a function for the origin parameter may enable Denial of Service (DoS) attacks. Craft these with extreme care.

    Supported values:

    • Boolean: true to reflect the request origin, false to disable CORS.
    • String: A specific origin (e.g., "http://example.com"). The special * value (default) allows any origin.
    • RegExp: A regular expression pattern to test the request origin.
    • Array: An array of valid origins (Strings or RegExps).
    • Function: A custom logic function with signature (origin, cb) => void. The callback expects err [Error | null], origin. The Fastify instance is bound to this inside the function.
    origin: (origin, cb) => {
      const hostname = new URL(origin).hostname
      if(hostname === "localhost"){
        //  Request from localhost will pass
        cb(null, true)
        return
      }
      // Generate an error on other origins, disabling access
      cb(new Error("Not allowed"), false)
    }
  5. Configure CORS with a delegator for dynamic origins

    main

    If you need to determine CORS settings dynamically (e.g., checking a database or a whitelist for each request), you can use a delegator function in the options object. The delegator can be a standard callback-style function or a function that returns a Promise.

    Callback style: delegator: (req, callback) => callback(null, 'https://allowed-origin.com')

    Promise style: delegator: (req) => Promise.resolve('https://allowed-origin.com')

    fastify.register(cors, {
      delegator: (req, next) => {
        const origin = req.headers.origin
        if (isAllowed(origin)) {
          next(null, origin)
        } else {
          next(new Error('Not allowed'))
        }
      }
    })
  6. How CORS preflight requests are handled

    main

    The plugin automatically handles OPTIONS preflight requests.

    1. It registers an OPTIONS * route to intercept preflight requests before other plugins (like authentication) can deny them.
    2. If preflight: true (default) and strictPreflight: true (default), the plugin validates that the request contains the required origin and access-control-request-method headers, returning a 400 if they are missing.
    3. If preflightContinue is false (default), the plugin sends a response immediately (e.g., 204 No Content) and terminates the request lifecycle for that preflight. If true, it allows the request to proceed to subsequent hooks.
  7. Register @fastify/cors plugin

    main

    To enable CORS in your Fastify application, register the @fastify/cors plugin. You can pass a configuration object or a delegator function to dynamically resolve CORS options based on the request.

    const fastify = require('fastify')()
    const cors = require('@fastify/cors')
    
    fastify.register(cors, {
      origin: 'https://example.com',
      methods: 'GET,HEAD,POST'
    })
  8. Customize the Fastify hook name

    main

    By default, @fastify/cors uses the onRequest hook. You can change this to any valid Fastify hook name to control when CORS validation and header injection occur.

    import Fastify from 'fastify'
    import cors from '@fastify/cors'
    
    const fastify = Fastify()
    await fastify.register(cors, {
      hook: 'preHandler',
    })
    
    fastify.get('/', (req, reply) => {
      reply.send({ hello: 'world' })
    })
  9. Reference: @fastify/cors configuration options

    main

    A complete list of available configuration options for @fastify/cors.

    * `origin`: Configures the Access-Control-Allow-Origin CORS header.
    * `methods`: Configures the Access-Control-Allow-Methods CORS header. Expects a comma-delimited string or an array. Default: `GET,HEAD,POST`.
    * `hook`: Custom Fastify hook name. Default: `onRequest`.
    * `allowedHeaders`: Configures the Access-Control-Allow-Headers CORS header. Expects a comma-delimited string or an array.
    * `exposedHeaders`: Configures the Access-Control-Expose-Headers CORS header. Expects a comma-delimited string or an array.
    * `credentials`: Configures the Access-Control-Allow-Credentials CORS header. Set to `true` to pass the header.
    * `maxAge`: Configures the Access-Control-Max-Age CORS header in seconds.
    * `cacheControl`: Configures the Cache-Control header for CORS preflight responses. Can be an integer (as `max-age=${val}`) or a string.
    * `preflightContinue`: Passes the CORS preflight response to the route handler. Default: `false`.
    * `optionsSuccessStatus`: Status code for successful OPTIONS requests.
    * `preflight`: Disables preflight by passing `false`. Default: `true`.
    * `strictPreflight`: Enforces strict requirements for preflight request headers. Default: `true`.
    * `hideOptionsRoute`: Hides the options route from @fastify/swagger. Default: `true`.
    * `logLevel`: Sets the Fastify log level for the internal CORS pre-flight route.
  10. Override CORS settings for specific routes

    main

    You can override the global CORS configuration for individual routes by using the config.cors key in the route definition. Setting cors: false will disable CORS for that specific route.

    // Disable CORS for this specific route
    fastify.get('/no-cors', {
      config: {
        cors: false
      }
    }, async (request, reply) => {
      return { hello: 'world' }
    })
    
    // Override with specific options
    fastify.get('/custom-cors', {
      config: {
        cors: {
          origin: 'https://specific-origin.com'
        }
      }
    }, async (request, reply) => {
      return { hello: 'world' }
    })