#http request blocked by cors

27 messages · Page 1 of 1 (latest)

golden oxide
#

Any idea why my request from localhost:3000 is still blocked by CORS? I copied the headers from a Convex sample.

I can call it from Postman but not React.

import { openai } from "@ai-sdk/openai";
import { getAuthUserId } from "@convex-dev/auth/server";
import { Message, streamText } from "ai";
import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";

const http = httpRouter();

http.route({
  path: "/api/chat",
  method: "POST",
  handler: httpAction(async (ctx, req) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) {
      return Response.json({ error: "Unauthorized" }, { status: 401 });
    }

    const { messages } = await req.json();

    const lastMessages = messages.slice(-30) as Message[];

    const result = streamText({
      model: openai("gpt-4o"),
      messages: lastMessages,
    });

    return result.toDataStreamResponse({
      headers: new Headers({
        "Access-Control-Allow-Origin": "*",
        Vary: "origin",
      }),
    });
  }),
});

http.route({
  path: "/api/chat",
  method: "OPTIONS",
  handler: httpAction(async (_, request) => {
    const headers = request.headers;
    if (
      headers.get("Origin") !== null &&
      headers.get("Access-Control-Request-Method") !== null &&
      headers.get("Access-Control-Request-Headers") !== null
    ) {
      return new Response(null, {
        headers: new Headers({
          "Access-Control-Allow-Origin": "*",
          "Access-Control-Allow-Methods": "POST",
          "Access-Control-Allow-Headers": "Content-Type, Digest",
          "Access-Control-Max-Age": "86400",
        }),
      });
    } else {
      return new Response();
    }
  }),
});


export default http;

lean hinge
#

I run a fork of convex helpers with debugging for cors - opened a PR to add that to the library: https://github.com/get-convex/convex-helpers/pull/590

If you want to use right away, I published my fork as well, you can temporarily alias it to debug:

npm i convex-helpers@npm:@erquhart/convex-helpers
// convex/http.ts
const cors = corsRouter(http, { debug: true })
golden oxide
lean hinge
#

It shouldn't be, what are you seeing?

#

It's a command to install @erquhart/convex-helpers, but let it be named convex-helpers in your node_modules and package.json

#

That way you don't have to update your code to temporarily use this fork

golden oxide
#

I can't figure out the import statement

lean hinge
#

You won't change the import statement, that's the value of using an alias

golden oxide
#

And my package.json entry looks like this: "convex-helpers": "npm:@erquhart/convex-helpers@^0.1.87",

lean hinge
#

oh shoot

#

you're not using the cors router helper, I just read "cors" in your post and assumed you were

golden oxide
#

It does look useful

lean hinge
golden oxide
#

I'll give it a try, but my Convex auth randomly stopped working

lean hinge
#

Wonder if your versions changed when you did that install

#

Can you run this and share the output:

npx envinfo --npmPackages
golden oxide
#

doesn't look like it

#

AuthProviderDiscoveryFailed but there are 0 Google results

golden oxide
#

@lean hinge Ok, the auth error is solved. But I'm still getting CORS error after adding the corsRouter.

lean hinge
#

okay, so maybe debug will help then

#
npm i convex-helpers@npm:@erquhart/convex-helpers
// convex/http.ts
const cors = corsRouter(http, { debug: true })
golden oxide
#
22.5.2025, 17:26:45 [CONVEX H(OPTIONS /api/chat)] [LOG] 'CORS request' {
  path: 'https://clean-deer-999.convex.site/api/chat',
  origin: 'http://localhost:3000',
  headers: Headers { host: 'clean-deer-999.convex.site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36', accept: '*/*', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9,de-DE;q=0.8,de;q=0.7,en-DE;q=0.6,ru;q=0.5', 'access-control-request-headers': 'authorization,content-type', 'access-control-request-method': 'POST', origin: 'http://localhost:3000', priority: 'u=1, i', referer: 'http://localhost:3000/', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'cross-site', 'x-forwarded-for': '88.74.147.132', 'x-forwarded-host': 'clean-deer-999.convex.site', 'x-forwarded-proto': 'https', 'convex-request-id': '83cfc13510ffe6c4' },
  method: 'OPTIONS',
  body: null
}

Can you see anything in here?

lean hinge
#

If there's no message after that saying it was blocked, the cors helper is allowing it through

#

What cors error(s) are you getting specifically? Is it from options or get/post request?

golden oxide
#

The options request gets through, but the post request doesn't

#

Maybe it works different because the AI SDK streams the response