{"id":13741171,"url":"https://github.com/ghivert/cors-builder","last_synced_at":"2026-03-16T06:35:23.524Z","repository":{"id":235568657,"uuid":"790921753","full_name":"ghivert/cors-builder","owner":"ghivert","description":"A CORS Builder, performing validation and injection of CORS for mist, wisp and any framework!","archived":false,"fork":false,"pushed_at":"2025-12-24T11:23:44.000Z","size":59,"stargazers_count":17,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-26T02:31:38.555Z","etag":null,"topics":["backend","cors","gleam","mist","server","wisp"],"latest_commit_sha":null,"homepage":"https://hexdocs.pm/cors_builder","language":"Gleam","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ghivert.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["ghivert"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2024-04-23T19:12:05.000Z","updated_at":"2025-12-24T11:23:23.000Z","dependencies_parsed_at":"2024-04-23T22:06:40.310Z","dependency_job_id":"1c0d9d40-b347-45a4-80c7-2ba56ecae919","html_url":"https://github.com/ghivert/cors-builder","commit_stats":null,"previous_names":["ghivert/simple-cors","ghivert/cors-builder"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/ghivert/cors-builder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghivert%2Fcors-builder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghivert%2Fcors-builder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghivert%2Fcors-builder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghivert%2Fcors-builder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ghivert","download_url":"https://codeload.github.com/ghivert/cors-builder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ghivert%2Fcors-builder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30570784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-16T06:02:37.763Z","status":"ssl_error","status_checked_at":"2026-03-16T06:02:14.913Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","cors","gleam","mist","server","wisp"],"created_at":"2024-08-03T04:00:56.278Z","updated_at":"2026-03-16T06:35:23.496Z","avatar_url":"https://github.com/ghivert.png","language":"Gleam","funding_links":["https://github.com/sponsors/ghivert"],"categories":["Packages"],"sub_categories":["HTTP"],"readme":"# CORS Builder\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Before diving in CORS,\n\u003e [make sure you're aware of security advices](#more-details--notes-about-security)\n\u003e and see if you can't just use a simple proxy to avoid CORS! It's a better and\n\u003e more secure way to manage CORS! Always secure correctly your CORS, and use\n\u003e them sparingly, when needed.\n\nManipulating CORS is often a pain for developers, and always a little blurry, to\nunderstand what should be done, how it should be configured, etc. CORS Builder\nabstract the complexity while trying to remains simple, and friendly warns you\nwhen something is wrong.\n\nCORS Builder is compatible with every servers, as long as you're using the\n[`gleam_http`](https://hexdocs.pm/gleam_http) `Response` as a foundation.\nHowever, to simplify your development, two middlewares are provided\nout-of-the-box:\n[`wisp_middleware`](https://hexdocs.pm/cors_builder/cors_builder.html#wisp_middleware)\nand\n[`mist_middleware`](https://hexdocs.pm/cors_builder/cors_builder.html#mist_middleware)\nto integrate nicely in [`wisp`](https://hexdocs.pm/wisp) and\n[`mist`](https://hexdocs.pm/mist). You should never have to worry about CORS\nagain! Use the package, configure your CORS, and everything should work\nsmoothly!\n\n## Quickstart\n\nYou can interchange `wisp_middleware` with `mist_middleware` if you're using\n`wisp` or `mist`.\n\n```gleam\nimport cors_builder as cors\nimport gleam/http\nimport mist\nimport wisp.{type Request, type Response}\n\nfn cors() {\n  cors.new()\n  |\u003e cors.allow_origin(\"http://localhost:3000\")\n  |\u003e cors.allow_origin(\"http://localhost:4000\")\n  |\u003e cors.allow_method(http.Get)\n  |\u003e cors.allow_method(http.Post)\n}\n\nfn handler(req: Request) -\u003e Response {\n  use req \u003c- cors.wisp_middleware(req, cors())\n  wisp.ok()\n}\n\nfn main() {\n  handler\n  |\u003e wisp.mist_middlewarer(secret_key)\n  |\u003e mist.new()\n  |\u003e mist.port(3000)\n  |\u003e mist.start_http()\n}\n```\n\n## More details \u0026 notes about security\n\nCORS are often badly understood, however they're full parts of the web stack\nwhen working with browsers, and they're part of security measures, to avoid\nusers' browsers behaving badly.\n\nCORS intervene when browsers have to manage with cross-origin requests. A\ncross-origin request is a request coming from a different domain than the domain\nyou're currently on. Imagine you're browsing your favorite website, like\n[packages.gleam.run](https://packages.gleam.run), and suddenlly, your browser\nwant to query [google.com](https://google.com) in an async way. Because you're\nnot on Google, the browser will identify your request as a cross-origin request.\nSome more security measures have to be taken to make sure the request is valid.\nThat's where CORS comes into play. CORS stands for Cross-Origin Resource\nSharing. It means it's a way to authorize cross-origin requests, to allow\noutside clients to access the desired resources.\n\nThis mechanism is a way to prevent browsers to ask for data on behalf of a user,\nin an undesired way. It's up to you, when developping your server, to make sure\nonly authentified, regular users can access your service. **It is a bad idea to\nlet everyone access your data directly from a browser.** You should identify who\ncan access your service, and how, that's what CORS are made for. Most of the\ntime, you want your frontend to access your backend, and nothing else. You can\nsimply identify those domains, and add them in your CORS configuration. Let's\nimagine your frontend is hosted on `https://frontend.app` and your backend on\n`https://backend.app`. You can configure your CORS to _only_ accept\n`https://frontend.app`. That way, every request coming from another domain will\nbe rejected, and only your users will be accepted.\n\nKeep in mind that CORS will never trigger as long as your frontend query the\nsame domain where it resides. When your frontend queries\n`https://frontend.app/api/path` for example, because your frontend resides on\n`https://frontend.app`, no cross-origin request is identified, so CORS won't\ncomes into play. So always think about this, and see if you can just host your\nfrontend at the same address as your backend. This can be achieved using a\nproxy, and this should be soon available in lustre dev tools, and is already\navailable if you're using\n[Vite](https://vitejs.dev/config/server-options#server-proxy) or\n[Webpack](https://webpack.js.org/configuration/dev-server/#devserverproxy)!\n\n## How are CORS working?\n\nBrowsers apply a simple rules for every HTTP request: when the request\noriginates from a different origin than the target server URL — and if it's not\na simple request — the browser needs to authorize the cross-origin call.\n\n\u003e From the HTTP point of view, a simple request respects the following\n\u003e conditions:\n\u003e\n\u003e - Allowed methods are `GET`, `HEAD` or `POST`\n\u003e - Allowed headers are `accept`, `accept-language`, `content-language` and\n\u003e   `content-type`\n\u003e - `content-type` should be:\n\u003e   - `application/x-www-form-urlencoded`\n\u003e   - `multipart/form-data`\n\u003e   - `text/plain`\n\u003e - No event listener has been added on `XMLHttpRequestUpload`.\n\u003e   `XMLHttpRequestUpload.upload` is preferred.\n\u003e - No `ReadableStream` is used in the request.\n\nTo authorize the call, the browser will issue a first request, called a\n\"preflight\" request. This request takes the form of an `OPTIONS` request, which\nshould be answered positively by the server (meaning the response status code\nshould be 2XX) and should contains the appropriate CORS headers\n(`access-control` headers).\n\nIn case the preflight request is not successful, the server will simply cancel\nthe HTTP request. But if the preflight request is successful, then the browser\nwill then launch the real request, and the server will be able to handle it.\n\n## What are the headers?\n\nWe distinguish different types of headers: the headers concerning the request\nissuer (the caller) and the headers responded by the server.\n\n\u003e [!NOTE]\n\u003e\n\u003e In HTTP, all headers keys are case-insensitive. It means all headers can be\n\u003e written as `content-type` or `Content-Type` or even `CONTENT-type`. By\n\u003e convention, they're written as `Content-Type`. In HTTP2 though, all headers\n\u003e keys have to be lowercase or the requests are rejected, and `gleam_http` will\n\u003e enforce this behaviour. All headers keys in this guide will be written in\n\u003e lowercase. On the internet you could still see both way of writing them.\n\n### Response headers\n\nResponse headers are not automatically set by the server, and you should handle\nthem according on what you want to do. This package tries to abstract it to\nsimplify your development and let you focus on your application. We count 6 CORS\nresponse headers:\n\n- `access-control-allow-origin`, indicates which origins are allowed to access\n  the server. It can be a joker (`\"*\"`) or a unique domain\n  (`https://gleam.run`). It cannot contains multiple domains, but can response\n  to multiple different domains with the `vary` header. You should not have to\n  take care of this, because the library provides it for you.\n- `access-control-expose-headers`, provides a whitelist of allowed headers for\n  the browsers. Only the headers in the whitelist will be able to be used in the\n  response object in the JS code. It means if the response contains headers you\n  want to cache to the client, you can use this header.\n- `access-control-max-age`, allows to put the preflight response in cache, for a\n  specified amount of time. This avoids to rerun the `OPTIONS` request multiple\n  times.\n- `access-control-allow-credentials`, allows the request to includes credentials\n  authorizations. This can expose you to CSRF attack. Never activate this option\n  unless you carefully know what you're doing.\n- `access-control-allow-methods`, provides a whitelist of subsequent authorized\n  methods in the future requests.\n- `access-control-allow-headers`, indicates which headers are accepted by the\n  server, and thus, which headers the browser will be able to send in subsequent\n  requests.\n\n### Request headers\n\nRequest headers are headers automatically set by the browser, when issuing a\nrequest with `XMLHttpRequest` or `fetch`. You should not bother about it, but\nthey're still referenced it, in case you encounter them.We count 3 CORS request\nheaders:\n\n- `origin` contains the origin of the request. The browser will _always_ fill\n  this header automatically.\n- `access-control-request-method` contains the desired methods to use when\n  talking with the server.\n- `access-control-request-header` contains the desired headers that the request\n  want to have.\n\n## Contributing\n\nYou love the package and want to improve it? You have a shiny new framework and\nwant to provide an integration with CORS in this package? Every contribution is\nwelcome! Feel free to open a Pull Request, and let's discuss about it!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghivert%2Fcors-builder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fghivert%2Fcors-builder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fghivert%2Fcors-builder/lists"}