Skip to main content
Deno 2 is finally here 🎉️
Learn more

cors-middleware

deno land deno doc GitHub release (latest by date) codecov GitHub

test NPM

HTTP cross-origin resource sharing(CORS) middleware.

Compliant with Fetch living standard, 3.2. CORS protocol.

Middleware

For a definition of Universal HTTP middleware, see the http-middleware project.

CORS request and CORS preflight request

A CORS request is a request with an Origin header.

On the other hand, a CORS preflight request is a CORS request and satisfies the following:

  • Method is Options
  • Includes Access-Control-Request-Method header
  • Includes Access-Control-Request-Headers header

This project provides middleware for CORS requests.

CORS request

Add a CORS header to the response in the downstream.

import {
  cors,
  type Handler,
} from "https://deno.land/x/cors_middleware@$VERSION/mod.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";

const middleware = cors();
const corsRequest = new Request("test:", {
  headers: { origin: "<origin>" },
});
declare const handler: Handler;

const response = await middleware(corsRequest, handler);

assert(response.headers.has("access-control-allow-origin"));

yield:

Access-Control-Allow-Origin: *
Vary: Origin

CORS request options

Name Type Description
allowOrigins * | (string | RegExp )[] Allowed origin list.
allowCredentials true | "true" Access-Control-Allow-Credentials
exposeHeaders string[] Access-Control-Expose-Headers

AllowOrigins

allowOrigins is a list of * or allowed origins.

The default is *.

If *, ACAO(*) is added to the response.

The list may consist of strings or regular expression objects.

The middleware compares the value of the Origin header with the allowOrigins.

If a match is found, ACAM(Origin) is added to the response.

If no match, ACAM("") is added to the response.

import {
  cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";

const middleware = cors({
  allowOrigins: ["https://test.example", /^https:\/\/cdn\..*/],
});

AllowCredentials

The allowCredentials value will serialize and added to the response as an ACAC (Access-Control-Allow-Credentials) header.

import {
  cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";

const middleware = cors({ allowCredentials: true });

yield:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Vary: Origin

ExposeHeaders

The value of exposeHeaders will serialize and added to the response as an ACEH (Access-Control-Expose-Headers) header.

However, if the request is a CORS preflight request, it is not added.

import {
  cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";

const middleware = cors({ exposeHeaders: ["x-test"] });

yield:

Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: x-test
Vary: Origin

CORS options serialization error

Each option will serialize.

If serialization fails, it throws an error as follows:

import {
  cors,
} from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";
import { assertThrows } from "https://deno.land/std/testing/asserts.ts";

const middleware = assertThrows(() =>
  cors({ exposeHeaders: ["<invalid:field-name>"] })
);

CORS preflight request

Create CORS preflight request handler.

import {
  type Handler,
  preflight,
} from "https://deno.land/x/cors_middleware@$VERSION/mod.ts";
import { assert } from "https://deno.land/std/testing/asserts.ts";
import { assertSpyCalls, spy } from "https://deno.land/std/testing/mock.ts";

const corsPreflightRequest = new Request("test:", {
  method: "OPTIONS",
  headers: {
    origin: "<origin>",
    "access-control-request-method": "POST",
    "access-control-request-headers": "content-type",
  },
});

declare const handler: Handler;
const next = spy(handler);
const handlePreflight = preflight();
const response = await handlePreflight(corsPreflightRequest, next);

assertSpyCalls(next, 0);
assert(response.status === 204);
assert(response.headers.has("access-control-allow-origin"));
assert(response.headers.has("access-control-allow-methods"));
assert(response.headers.has("access-control-allow-headers"));
assert(response.headers.has("vary"));

yield:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type
Vary: origin, access-control-request-method, access-control-request-headers

If the request is not a CORS preflight request, next will execute.

CORS preflight options

Name Type Description
allowMethods string[] Access-Control-Allow-Methods
allowHeaders string[] Access-Control-Allow-Headers
maxAge number Access-Control-Max-Age
status 200 | 204 Preflight response status code.

AllowMethods

The value of allowMethods will serialize and added to the response as an ACAM (Access-Control-Allow-Methods) header.

If not specified, ACRM (Access-Control-Request-Method) will add as ACAM to the response.

import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";

const handler = preflight({ allowMethods: ["POST", "PUT"] });

yield:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT
Access-Control-Allow-Headers: <Access-Control-Request-Headers>
Vary: origin, access-control-request-method, access-control-request-headers

AllowHeaders

The value of allowHeaders will serialize and added to the response as an ACAH (Access-Control-Allow-Headers) header.

If not specified, ACRH (Access-Control-Request-Headers) will add as ACAH to the response.

import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";

const handler = preflight({ allowHeaders: ["x-test1", "x-test2"] });

yield:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: <Access-Control-Request-Method>
Access-Control-Allow-Headers: x-test1, x-test2
Vary: origin, access-control-request-method, access-control-request-headers

MaxAge

The value of maxAge will serialize and added to the response as an ACMA (Access-Control-Max-Age) header.

import { preflight } from "https://deno.land/x/cors_middleware@$VERSION/middleware.ts";

const handler = preflight({ maxAge: 86400 });

yield:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: <Access-Control-Request-Method>
Access-Control-Allow-Headers: <Access-Control-Request-Headers>
Access-Control-Max-Age: 86400
Vary: origin, access-control-request-method, access-control-request-headers

Status

The default is 204 No Content.

You can change to 200 OK.

API

All APIs can be found in the deno doc.

License

Copyright © 2023-present httpland.

Released under the MIT license