{"id":22804427,"url":"https://github.com/bump-sh/cors-toujours","last_synced_at":"2025-04-22T06:56:31.704Z","repository":{"id":267596861,"uuid":"879088608","full_name":"bump-sh/cors-toujours","owner":"bump-sh","description":"This is a lightweight HTTP proxy server built using the Sinatra framework. It acts as a pass-through proxy, allowing requests to be forwarded to a specified target URL. Additionally, it provides a JWT (JSON Web Token) verification mechanism to allow only specific requests.","archived":false,"fork":false,"pushed_at":"2025-02-04T11:01:37.000Z","size":77,"stargazers_count":11,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-11T22:16:53.021Z","etag":null,"topics":["cors","cors-anywhere","cors-headers","cors-proxy","http","proxy","ruby","sinatra"],"latest_commit_sha":null,"homepage":"https://bump.sh","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bump-sh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-10-27T00:00:50.000Z","updated_at":"2025-02-14T13:56:13.000Z","dependencies_parsed_at":"2024-12-11T09:32:01.194Z","dependency_job_id":"43d5d594-16c7-4a69-b6ff-2f5d5ebc2fbd","html_url":"https://github.com/bump-sh/cors-toujours","commit_stats":null,"previous_names":["bump-sh/cors-toujours"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bump-sh%2Fcors-toujours","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bump-sh%2Fcors-toujours/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bump-sh%2Fcors-toujours/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bump-sh%2Fcors-toujours/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bump-sh","download_url":"https://codeload.github.com/bump-sh/cors-toujours/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249836554,"owners_count":21332308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["cors","cors-anywhere","cors-headers","cors-proxy","http","proxy","ruby","sinatra"],"created_at":"2024-12-12T10:08:08.492Z","updated_at":"2025-04-20T01:27:44.020Z","avatar_url":"https://github.com/bump-sh.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Proxy Server with JWT Authentication\n\nThis is a lightweight HTTP proxy server built using the Sinatra framework. It acts as a pass-through proxy, allowing requests to be forwarded to a specified target URL. Additionally, it provides a JWT (JSON Web Token) verification mechanism to allow only specific requests.\n\nPowered and used in production by [Bump.sh](https://bump.sh)\n\n## Features\n\n- **CORS Support**: Handles CORS headers, allowing cross-origin requests.\n- **JWT verification**: Verifies the presence and validity of the `x-cors-toujours-token` header to ensure requests are allowed.\n- **Flexible HTTP Method Support**: Supports `GET`, `POST`, `PUT`, `PATCH`, and `DELETE` methods for forwarding client requests to the target server.\n- **Automatic Request Forwarding**: Forwards requests to the specified target URL while preserving headers and request bodies.\n- **Path Parameter Support**: Supports dynamic path parameters in URL patterns (e.g., `/posts/{post_id}/comments/{id}`).\n\n## Getting Started\n\n### Prerequisites\n\n- Ruby (\u003e= 3.0)\n- Bundler\n\nInstall the required gems:\n```bash\nbundle install\n```\n\n### Configuration\n\nThe proxy is configured via environment variables. In local or test environment you can set those variables thanks to a `.env` file.\n\n#### JWT signing keys\n\nUse the following script to create your first JWT signing keys:\n```bash\n./rotate_keys.rb\n```\n\nThis will generate a RSA key pair and add it to the `.env` file with the following variables:\n- `JWT_SIGNING_PUBLIC_KEY`: Public key for token verification (used by the proxy)\n- `JWT_SIGNING_PRIVATE_KEY`: Private key for token signing (used by the server exposing a web HTTP client allowing only specific requests)\n\nIf later on you need to rotate the keys you will need to remove them manually from the .env file before exectuting the script again.\n\n#### `x-cors-toujours-token` header\n\nBy default, the proxy will read the verification token from the header `x-cors-toujours-token`. You can change the name of the header by adding the following environment variable to your `.env` file:\n\n- `CORS_TOUJOURS_TOKEN_HEADER=\"x-my-custom-header-name\"`\n\n### Starting the Server Locally\n\nRun the following command to start the server on port 4567:\n```bash\nbundle exec puma\n```\n\n### Run the Tests\n\nRun the following command to run the test suite:\n```bash\nbundle exec rspec --color -fd spec\n```\n\n## Usage\n\n### Authentication\n\nThe server verifies the `x-cors-toujours-token` header for every request (name of the header is customizable - see [configuration details](#configuration)). The JWT token must contain the following claims:\n\n- `servers`: Array of allowed target server URLs\n- `verb`: Allowed HTTP method for the request to be made (GET, POST, PUT, PATCH, or DELETE)\n- `path`: Allowed path pattern, supporting path parameters (e.g., `/posts/{post_id}`)\n- `exp`: Token expiration timestamp\n\nE.g.: A client sending a request to `GET https://bump.sh/api/v1/ping`\nvia the proxy will need to include an encoded JWT token in\nthe `x-cors-toujours-token` header, whose decoded value would look like:\n```json\n{\n  \"servers\": [\"https://bump.sh\"],\n  \"path\": \"/api/v1/ping\",\n  \"verb\": \"GET\",\n  \"exp\": \"2025-01-01T00:00:00Z\"\n}\n```\n\nIf the token is missing, invalid, or doesn't meet those requirements,\nthe request will be rejected with a `403 Forbidden` HTTP error.\n\n### Path Parameters\n\nThe server supports dynamic path parameters in URL patterns. For example:\n- Pattern: `/posts/{post_id}/comments/{id}`\n- Valid URL: `/posts/123/comments/456`\n\n### Example Requests\n\n**GET request:**\n```bash\ncurl -X GET \"http://localhost:4567/https://jsonplaceholder.typicode.com/todos\" \\\n     -H \"x-cors-toujours-token: YOUR_JWT_TOKEN\"\n```\n\n**PATCH request:**\n```bash\ncurl -X PATCH \"http://localhost:4567/https://jsonplaceholder.typicode.com/posts/1\" \\\n     -H \"Content-Type: application/json\" \\\n     -H \"x-cors-toujours-token: YOUR_JWT_TOKEN\" \\\n     -d '{\"title\":\"foo\"}'\n```\n\n### CORS Support\n\nThe server includes the following CORS headers for cross-origin access:\n- `Access-Control-Allow-Origin: *`\n- `Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, PATCH, DELETE`\n- `Access-Control-Allow-Headers: Content-Type, Authorization, x-cors-toujours-token, x-requested-with`\n\nPreflight OPTIONS requests are handled automatically.\n\n## Error Handling\n\nThe server returns different status codes based on various error conditions:\n\n- **401 Unauthorized**:\n  - Missing `x-cors-toujours-token` header\n  - Invalid JWT token\n  - Expired token\n\n- **403 Forbidden**:\n  - HTTP method doesn't match the token's `verb` claim\n  - Target server not in the token's `servers` list\n  - Request path doesn't match the token's `path` pattern\n\n- **502 Bad Gateway**:\n  - Issues communicating with the target server\n\nEach error response includes a JSON body with an `error` field describing the specific error.\n\n## License\n\nThis project is licensed under the AGPL License.\n\n## Contributing\n\nFeel free to open issues and submit pull requests!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbump-sh%2Fcors-toujours","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbump-sh%2Fcors-toujours","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbump-sh%2Fcors-toujours/lists"}