Grant CORS to the right origins only

An API reflects whatever Origin a request carries and allows credentials, so any website can read a signed-in user’s data from it. Repair the CORS policy so it grants access only to the configured origins and keeps caches correct.

Requires Node.js 22 or newer. No package installation or server needed. To work in a container instead, open the folder with VS Code Dev Containers or GitHub Codespaces: .devcontainer/devcontainer.json uses the Dev Containers Node.js 24 image, pinned by digest.
1. Unzip all files into one folder.
2. In that folder, run: node --test exercise.test.mjs
3. Edit cors-policy.mjs, then run the same command again.

The starter deliberately fails some tests. A successful repair passes every case, including cases that catch common wrong fixes. The browser runs this same cases.mjs with the same fixtures; locally Node runs your code directly. If you completed the optional first stage in the browser, Download my work adds your input as stage1-input.json and the tests include it. Only run code you wrote or reviewed.

1. Reproduce the reflection
Run the starter. It copies the request’s Origin into Access-Control-Allow-Origin and allows credentials, so the evil-origin case is granted access to a cookie-authenticated API.

2. Always vary on Origin
Return {Vary: "Origin"} as the base of every response, granted or refused, so a cache neither serves one origin’s grant to another nor replays a stored refusal to an allowed origin.

3. Grant only an exact match
Add the Allow-Origin and Allow-Credentials headers only when allowedOrigins.includes(origin). A missing origin, the string "null", and a host that merely ends with or contains the trusted name get no grant.

4. Answer the preflight
For OPTIONS from an allowed origin, add the allowed methods, allowed headers and max-age. The preflight is a protocol question, not the authorized request, so authentication and CSRF checks still run on the real request.

SUPPLIED CONTRACT
corsHeaders(method, origin, allowedOrigins) returns an object of response headers. method is the normalized HTTP method; origin is the request’s Origin header value, or undefined when there is none; allowedOrigins is an array of exact origin strings such as https://portal.example.test. This API uses cookies, so it must never combine a wildcard with credentials and must never reflect an untrusted origin. Always set Vary to "Origin", because the response depends on the Origin header. When origin is one of allowedOrigins exactly, set Access-Control-Allow-Origin to that origin and Access-Control-Allow-Credentials to "true"; for an OPTIONS preflight also set Access-Control-Allow-Methods to "GET, POST", Access-Control-Allow-Headers to "Content-Type, X-CSRF-Token" and Access-Control-Max-Age to "600". When the origin is missing or not allowed, return only the Vary header. Compare whole origins: no suffix, prefix or substring matching, and the string "null" is never an allowed origin.

REFERENCE
reference.mjs contains an explained solution: For https://portal.example.test a GET returns Vary, Allow-Origin set to that origin and Allow-Credentials true; an OPTIONS adds the methods, headers and 600-second max-age. https://reports.example.test, the second configured origin, is granted too. https://evil.test, http://portal.example.test (wrong scheme), https://portal.example.test.evil.test (suffix), https://evil-portal.example.test (substring), the literal "null" and a missing origin all receive only Vary, with no Allow-Origin. The wildcard "*" is never produced, so it can never combine with credentials.

SCOPE
This is the CORS header policy, not the whole request path. CORS is a browser read-permission decision: it does not authenticate the user, authorize the object or stop CSRF, which still need cookies with SameSite, a CSRF token and server-side checks on the actual request. The lab uses exact string origins and a fixed method and header list; a real API also validates the requested method and headers on the preflight and sets an appropriate cache lifetime.

NEXT TASK
Which of your API responses set Access-Control-Allow-Origin by reflecting the request, and do any set it together with Allow-Credentials?

SOURCE
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS
