Skip to content

feat(api): add CORS headers for browser clients#94

Closed
MaudeBot wants to merge 1 commit intoopenclaw:mainfrom
MaudeCode:feat/cors-headers
Closed

feat(api): add CORS headers for browser clients#94
MaudeBot wants to merge 1 commit intoopenclaw:mainfrom
MaudeCode:feat/cors-headers

Conversation

@MaudeBot
Copy link

@MaudeBot MaudeBot commented Feb 1, 2026

Summary

Adds CORS headers to all API endpoints, enabling browser-based clients to fetch skills directly from the ClawHub API.

Motivation

Browser-based tools like Cove (OpenClaw WebUI) want to display and install skills from ClawHub. Currently, browsers block these requests due to missing CORS headers.

This is standard practice for public package registries — npm, crates.io, and PyPI all allow cross-origin requests.

Changes

  • convex/lib/cors.ts — Shared CORS headers and preflight response helper
  • convex/http.ts — Single OPTIONS handler for all /api/* routes
  • convex/httpApi.ts — CORS headers in json/text response helpers
  • convex/httpApiV1.ts — CORS headers in json/text helpers + file content endpoints
  • convex/downloads.ts — CORS headers on download responses

Headers Added

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

Safety

  • Additive only — Existing CLI/server clients ignore these headers
  • Auth unchanged — Protected endpoints still require Bearer tokens
  • No credentials mode — Not setting Allow-Credentials, so cookies aren't sent
  • Standard pattern — Identical to other public package registries

Greptile Overview

Greptile Summary

Adds CORS headers across all API endpoints to enable browser-based clients to fetch skills from ClawHub. The implementation is clean and additive - existing CLI/server clients will ignore these headers, and authentication still requires Bearer tokens for protected endpoints.

Key changes:

  • Created shared convex/lib/cors.ts module with standard CORS headers and preflight handler
  • Added CORS headers to all JSON/text response helpers in httpApi.ts and httpApiV1.ts
  • Added CORS headers to download endpoint responses in downloads.ts
  • Registered OPTIONS preflight handler for /api/* routes in http.ts

The approach follows standard patterns used by public package registries like npm and crates.io. No security concerns since Access-Control-Allow-Credentials is not set, so cookies/credentials won't be sent in cross-origin requests.

Confidence Score: 4/5

  • This PR is safe to merge with low risk
  • The implementation is additive and well-structured, following standard CORS patterns. Auth remains unchanged with Bearer tokens still required. However, two minor issues flagged in previous review threads (OPTIONS handler scope and narrow Allow-Headers list) could cause preflight failures for some legitimate browser requests, warranting minor attention before merge.
  • Previous review comments on convex/http.ts:199 and convex/lib/cors.ts:8 should be addressed to ensure comprehensive CORS coverage

Last reviewed commit: 29e8ec2

- Add convex/lib/cors.ts with shared CORS headers and preflight handler
- Update httpApi.ts and httpApiV1.ts json/text helpers to include CORS headers
- Update downloads.ts to include CORS headers on all responses
- Add single OPTIONS handler for /api/* prefix in http.ts

This enables browser-based clients (like Cove WebUI) to fetch skills
directly from the ClawHub API without CORS errors.

Allows: GET, POST, DELETE, OPTIONS from any origin (*)
@vercel
Copy link
Contributor

vercel bot commented Feb 1, 2026

@MaudeBot is attempting to deploy a commit to the Amantus Machina Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +199 to +204
// CORS preflight handler for all API routes
http.route({
pathPrefix: '/api/',
method: 'OPTIONS',
handler: corsPreflightHttp,
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] OPTIONS preflight only registered for /api/ prefix

This adds an OPTIONS handler only for pathPrefix: '/api/' (convex/http.ts:199-204). However, this router also exposes LegacyApiRoutes.* (still under /api in many setups) and potentially other non-/api/ HTTP routes (e.g., auth routes). If any of those endpoints are called cross-origin and trigger a preflight, they’ll still fail with a missing/404 OPTIONS route even though the GET/POST responses now include CORS headers.

If the intent is “all API endpoints,” consider also covering legacy routes (and/or the auth routes) with an OPTIONS handler that matches their prefixes.

Prompt To Fix With AI
This is a comment left during a code review.
Path: convex/http.ts
Line: 199:204

Comment:
[P1] OPTIONS preflight only registered for `/api/` prefix

This adds an OPTIONS handler only for `pathPrefix: '/api/'` (`convex/http.ts:199-204`). However, this router also exposes `LegacyApiRoutes.*` (still under `/api` in many setups) and potentially other non-`/api/` HTTP routes (e.g., auth routes). If any of those endpoints are called cross-origin and trigger a preflight, they’ll still fail with a missing/404 OPTIONS route even though the GET/POST responses now include CORS headers.

If the intent is “all API endpoints,” consider also covering legacy routes (and/or the auth routes) with an OPTIONS handler that matches their prefixes.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +8 to +13
export const CORS_HEADERS = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400', // 24 hours
} as const
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Access-Control-Allow-Headers may be too narrow for real browser clients

CORS_HEADERS hard-codes 'Access-Control-Allow-Headers': 'Content-Type, Authorization' (convex/lib/cors.ts:8-13). In practice, browser requests can include other headers that trigger a preflight (e.g., Accept, If-None-Match, Range, X-Requested-With). If a client sends any additional header, the preflight will be rejected even though the server is otherwise willing to serve the request.

Consider either echoing Access-Control-Request-Headers or broadening this list to the headers your clients actually send.

Prompt To Fix With AI
This is a comment left during a code review.
Path: convex/lib/cors.ts
Line: 8:13

Comment:
[P2] `Access-Control-Allow-Headers` may be too narrow for real browser clients

`CORS_HEADERS` hard-codes `'Access-Control-Allow-Headers': 'Content-Type, Authorization'` (`convex/lib/cors.ts:8-13`). In practice, browser requests can include other headers that trigger a preflight (e.g., `Accept`, `If-None-Match`, `Range`, `X-Requested-With`). If a client sends any additional header, the preflight will be rejected even though the server is otherwise willing to serve the request.

Consider either echoing `Access-Control-Request-Headers` or broadening this list to the headers your clients actually send.

How can I resolve this? If you propose a fix, please make it concise.

@MaudeBot
Copy link
Author

Closing - CORS was addressed in #296. Thanks!

@MaudeBot MaudeBot closed this Feb 14, 2026
@MaudeBot MaudeBot reopened this Feb 14, 2026
@MaudeBot MaudeBot closed this Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant