Home → Help

CORS error calling an AI API from the browser

Call the API from your own server, not from the page. The CORS block is doing its job: a request the browser can make is a request any visitor can read, including the key in its Authorization header.

What you are seeing

Why it happens

I

t

i

s

t

e

m

p

t

i

n

g

t

o

r

e

a

d

t

h

i

s

a

s

a

c

o

n

f

i

g

u

r

a

t

i

o

n

p

r

o

b

l

e

m

a

d

d

a

n

o

r

i

g

i

n

,

s

h

i

p

t

h

e

f

e

a

t

u

r

e

.

B

u

t

w

o

r

k

t

h

r

o

u

g

h

w

h

a

t

a

s

u

c

c

e

s

s

f

u

l

b

r

o

w

s

e

r

c

a

l

l

m

e

a

n

s

.

T

h

e

k

e

y

t

r

a

v

e

l

s

i

n

a

h

e

a

d

e

r

t

h

e

u

s

e

r

'

s

o

w

n

d

e

v

t

o

o

l

s

d

i

s

p

l

a

y

i

n

f

u

l

l

.

I

t

i

s

i

n

t

h

e

b

u

n

d

l

e

i

f

y

o

u

i

n

l

i

n

e

d

i

t

,

a

n

d

i

n

t

h

e

n

e

t

w

o

r

k

t

a

b

i

f

y

o

u

d

i

d

n

o

t

.

A

n

y

o

n

e

w

h

o

o

p

e

n

s

t

h

e

p

a

g

e

h

a

s

i

t

.

K

e

y

s

l

e

a

k

e

d

t

h

i

s

w

a

y

a

r

e

n

o

t

a

t

h

e

o

r

e

t

i

c

a

l

r

i

s

k

.

P

u

b

l

i

c

c

o

d

e

s

e

a

r

c

h

s

u

r

f

a

c

e

s

t

h

e

m

c

o

n

t

i

n

u

o

u

s

l

y

,

a

n

d

a

s

t

o

l

e

n

k

e

y

a

g

a

i

n

s

t

a

p

a

y

-

p

e

r

-

t

o

k

e

n

A

P

I

c

o

n

v

e

r

t

s

d

i

r

e

c

t

l

y

i

n

t

o

s

o

m

e

o

n

e

e

l

s

e

'

s

b

i

l

l

o

n

y

o

u

r

a

c

c

o

u

n

t

.

T

h

i

s

i

s

w

h

y

m

o

s

t

p

r

o

v

i

d

e

r

s

s

e

t

a

r

e

s

t

r

i

c

t

i

v

e

a

l

l

o

w

-

o

r

i

g

i

n

r

a

t

h

e

r

t

h

a

n

<

c

o

d

e

>

*

<

/

c

o

d

e

>

n

o

t

a

n

o

v

e

r

s

i

g

h

t

,

a

d

e

l

i

b

e

r

a

t

e

r

e

f

u

s

a

l

.

T

h

e

p

r

o

x

y

p

a

t

t

e

r

n

i

s

t

h

r

e

e

o

r

f

o

u

r

l

i

n

e

s

o

f

s

e

r

v

e

r

c

o

d

e

:

y

o

u

r

p

a

g

e

c

a

l

l

s

y

o

u

r

b

a

c

k

e

n

d

,

y

o

u

r

b

a

c

k

e

n

d

h

o

l

d

s

t

h

e

k

e

y

a

n

d

c

a

l

l

s

t

h

e

p

r

o

v

i

d

e

r

.

I

t

a

l

s

o

g

i

v

e

s

y

o

u

t

h

e

p

l

a

c

e

t

o

p

u

t

p

e

r

-

u

s

e

r

r

a

t

e

l

i

m

i

t

s

a

n

d

s

p

e

n

d

c

a

p

s

,

w

h

i

c

h

y

o

u

w

a

n

t

a

n

y

w

a

y

.

Confirm it is this

Ask the endpoint what origins it actually allows:

curl -s -I -X OPTIONS 'YOUR_BASE_URL/chat/completions' \
  -H 'Origin: https://example.com' \
  -H 'Access-Control-Request-Method: POST' \
  | grep -i 'access-control'

If Access-Control-Allow-Origin comes back as a specific domain rather than *, browser calls from your origin are not going to work, and no amount of client-side change will alter that.

How to fix it

  1. Put one endpoint on your own backendYour page posts to /api/chat on your own domain; that handler adds the Authorization header and forwards the request. No CORS involved, because the browser only ever talks to your origin.
  2. Never use a build-time public prefix for a keyNEXT_PUBLIC_, VITE_ and REACT_APP_ variables are compiled into the JavaScript you ship. A key placed there is published, not configured.
  3. Rotate anything that has already shippedIf a key has been in a deployed bundle, treat it as public and replace it. Rotation is cheap; an unbounded bill is not.
  4. Add per-user limits at your proxyOnce traffic passes through your own handler you can cap spend per session. Calling the provider directly from the browser gives you nowhere to enforce that.
APICLAN's API host allows only https://apiclan.us as an origin, deliberately — keys are meant to live on a server. Base URL setup for server-side clients is in the quickstart.

Related

Unexpected token '<' when calling an OpenAI-compatible API401 invalid API key — when the key looks right but still fails

Last checked 2026-09-09. Written from problems diagnosed on a live OpenAI-compatible gateway, not collected from other sites.