72-Nodejs Course 2023: The Bloody Cors
Hasan Zohdy
Posted on November 26, 2022
What is CORS?
CORS stands for Cross-Origin Resource Sharing
. It is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. A web page may freely embed cross-origin images, stylesheets, scripts, iframes, and videos. Certain "cross-domain" requests, notably Ajax requests, are forbidden by default by the same-origin security policy.
In Simple Words?
Simply put, Cors
allows us to whitelist the domains that can access our API. It is a security mechanism that prevents unauthorized access to our API.
For example, our nodejs application is going to be API
application, so we can define who is allowed to access our API. For example, we can allow localhost:3000
to access our API, but we can also allow localhost:3001
to access our API. So, we can define a list of domains that are allowed to access our API.
So it is a sort of a middleware
as well such as our previous throttle
article one.
How does Cors work?
It basically has multiple functionalities, it can white/black list any of the following:
- Certain Domains
- Certain HTTP Methods
- Certain HTTP Headers
What is an Origin?
An origin is a combination of URI scheme, host name, and port number. For example, https://www.example.com:443
is an origin. The origin of a resource is the origin of the server that served the resource. For example, if you visit https://www.example.com:443
and it returns a resource that has a URL of https://www.example.com:443/foo/bar
, the origin of the resource is https://www.example.com:443
.
So we can simply say that origin
is the combination of protocol
, domain
/ sub-domain
and port
.
Preflight Request
When a request is made to an API, the browser will first send a preflight
request to the API to check if the request is allowed. If the request is allowed, then the browser will send the actual request.
What is a Preflight Request?
A preflight request is simply a OPTIONS
request that is sent to the API to check if the request is allowed. If the request is allowed, then the browser/client side will send the actual request such as GET
, POST
, PUT
, DELETE
etc.
That's where mostly the OPTIONS
request method is used in.
How to Implement?
We can use fastify-cors plugin to implement Cors
in our application.
Installation
yarn add @fastify/cors
Usage
As mentioned in the docs, we need first to register our plugin and its options.
We're going to use the dynamic import as we did earlier to import our plugin.
// src/core/http/plugins.ts
import fastifyJwt from "@fastify/jwt";
import fastifyMultipart from "@fastify/multipart";
import { registerPlugin } from "./server";
export default async function registerHttpPlugins() {
// 👇🏻 register rate-limit plugin
await registerPlugin(import("@fastify/rate-limit"), {
// max requests per time window
max: 10,
// maximum time that is will allow max requests
timeWindow: 60 * 1000,
});
// 👇🏻 register cors plugin
await registerPlugin(import("@fastify/cors"), {
// options list
});
// import multipart plugin
registerPlugin(fastifyMultipart, {
attachFieldsToBody: true,
});
// use the jwt plugin with your preferred secret key
registerPlugin(fastifyJwt, {
secret: "my-secret",
});
}
Nothing new here, we just imported our new cors plugin.
Options
We can pass options to our cors plugin, for example, we can allow localhost:3000
to access our API.
// src/core/http/plugins.ts
import fastifyJwt from "@fastify/jwt";
/// ...
// 👇🏻 register cors plugin
await registerPlugin(import("@fastify/cors"), {
// options list
origin: ["http://localhost:3000"],
});
In the previous code, we allowed localhost:3000
to access our API, so any other origin will not be allowed to access our API.
Allowing All Origins
We can also allow all origins to access our API, but this is not recommended as it is a security risk.
// src/core/http/plugins.ts
import fastifyJwt from "@fastify/jwt";
/// ...
// 👇🏻 register cors plugin
await registerPlugin(import("@fastify/cors"), {
// options list
origin: "*",
});
This will allow all origins to access our API.
Black/White Listing Origins
The plugin doesn't give as the ability to whitelist/blacklist certain HTTP methods, so we need to do it manually, this can be done by using custom origin
function.
// src/core/http/plugins.ts
import fastifyJwt from "@fastify/jwt";
/// ...
// 👇🏻 register cors plugin
await registerPlugin(import("@fastify/cors"), {
// options list
origin: (origin, callback) => {
// whitelist certain domains
if (origin === "http://localhost:3000") {
callback(null, true);
return;
}
// blacklist certain domains
if (origin === "http://localhost:3001") {
callback(new Error("Not allowed"), false);
return;
}
// allow all origins
callback(null, true);
},
});
Of course we are not going to use it like this, i'm just giving an example of how we can implement it later, this can be in our next Break
article or so.
Why am i calling it Bloody CORS? 😁
Well, because when i started working with APIs, it was really pretty annoying to me to understand how it works and apply it with my Client side applications that connects to my API Applications, i was always getting an error message because of Cors says: No 'Access-Control-Allow-Origin' header is present on the requested resource.
That's why i was (and still) calling it Bloody CORS
😁
🎨 Conclusion
In this article, we learned how to implement Cors
in our application, we also learned what is Cors
and how it works.
We didn't set any configurations yet for our Cors
plugin, we will do it later as we go through our application.
☕♨️ Buy me a Coffee ♨️☕
If you enjoy my articles and see it useful to you, you may buy me a coffee, it will help me to keep going and keep creating more content.
🚀 Project Repository
You can find the latest updates of this project on Github
😍 Join our community
Join our community on Discord to get help and support (Node Js 2023 Channel).
🎞️ Video Course (Arabic Voice)
If you want to learn this course in video format, you can find it on Youtube, the course is in Arabic language.
📚 Bonus Content 📚
You may have a look at these articles, it will definitely boost your knowledge and productivity.
General Topics
- Event Driven Architecture: A Practical Guide in Javascript
- Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript
- After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
Packages & Libraries
- Collections: Your ultimate Javascript Arrays Manager
- Supportive Is: an elegant utility to check types of values in JavaScript
- Localization: An agnostic i18n package to manage localization in your project
React Js Packages
Courses (Articles)
Posted on November 26, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.