-
Notifications
You must be signed in to change notification settings - Fork 14
Description
Bug Description
Hi community!
I'm encountering a very strange issue with Next.js Server Components and the official Strapi JS library (@strapi/sdk-js). When I make requests to my Strapi backend from within a Server Component using the Strapi JS library, the Content-Type and Authentication headers are mysteriously missing in the outbound request. This results in a 403 error from Strapi.
Here's the breakdown of what I've observed:
Server Components + Strapi JS Library: Headers (Content-Type, Authentication) are missing in the request. Strapi returns 403.
Client Components + Strapi JS Library: Headers are present, request is successful, Strapi works as expected.
Direct Node.js script (using this demo outside Next.js) + Strapi JS Library: Headers are present, request is successful, Strapi works as expected.
Server Components + fetch or axios: Headers are present, request is successful, Strapi works as expected.
This isolates the issue specifically to the combination of Next.js Server Components and the Strapi JS library. It's not a general networking problem in Server Components because fetch and axios work fine. It's also not a fundamental issue with the Strapi JS library itself, as it works in other contexts.
Steps to Reproduce
Steps to Reproduce
- clone this simple demo repo: https://github.com/DebugNinjaSlayer/missing-header-demo
- yarn
- yarn dev
- access http://127.0.0.1:3000
- there should be error logs on server like this
Running with api token e4525f6cb23fd4c477b0071d067b31701f481678d1f022bf3eddbffb3e3494830cfe5feab5fa09f7a33ecd27b105a20bd22f3028250afb67dad85770f7e687b5b3e0697e4a3eac4362782d074157521c78512d9d2d1b4900b072813942eabf991addfa9ba5c35c530b3949e0dd05a64296eadca877cdc2360b54609e3529c470
Error [HTTPForbiddenError]: Request failed with status code 403 Forbidden: GET http://localhost:1337/api/categories
at <unknown> (HTTPForbiddenError: Request failed with status code 403 Forbidden: GET http://localhost:1337/api/categories)
at async Home (src/app/page.tsx:17:17)
15 | const categories = sdk.collection("categories");
16 |
> 17 | const docs = await categories.find();
| ^
18 | console.dir(docs, { depth: null });
19 | } catch (error) {
20 | console.log(error); {
response: Response {
status: 403,
statusText: 'Forbidden',
headers: Headers {
'content-security-policy': "connect-src 'self' https:;img-src 'self' data: blob: market-assets.strapi.io course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;media-src 'self' data: blob: market-assets.strapi.io course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;frame-src 'self' youtube.com www.youtube.com vimeo.com *.vimeo.com facebook.com www.facebook.com course-hosting-kit-dev.ccdf58dba7baa04c265641c25962951d.r2.cloudflarestorage.com;default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline'",
'referrer-policy': 'no-referrer',
'strict-transport-security': 'max-age=31536000; includeSubDomains',
'x-content-type-options': 'nosniff',
'x-dns-prefetch-control': 'off',
'x-download-options': 'noopen',
'x-frame-options': 'SAMEORIGIN',
'x-permitted-cross-domain-policies': 'none',
vary: 'Origin',
'access-control-allow-origin': '',
'access-control-allow-credentials': 'true',
'content-type': 'application/json; charset=utf-8',
'x-powered-by': 'Strapi <strapi.io>',
'content-length': '95',
date: 'Wed, 12 Feb 2025 06:50:10 GMT',
connection: 'keep-alive',
'keep-alive': 'timeout=5'
},
body: undefined,
bodyUsed: false,
ok: false,
redirected: false,
type: 'basic',
url: 'http://localhost:1337/api/categories'
},
request: Request {
method: 'GET',
url: 'http://localhost:1337/api/categories',
headers: Headers {
'Content-Type': 'application/json',
Authorization: 'Bearer e4525f6cb23fd4c477b0071d067b31701f481678d1f022bf3eddbffb3e3494830cfe5feab5fa09f7a33ecd27b105a20bd22f3028250afb67dad85770f7e687b5b3e0697e4a3eac4362782d074157521c78512d9d2d1b4900b072813942eabf991addfa9ba5c35c530b3949e0dd05a64296eadca877cdc2360b54609e3529c470'
},
destination: '',
referrer: 'about:client',
referrerPolicy: '',
mode: 'cors',
credentials: 'same-origin',
cache: 'default',
redirect: 'follow',
integrity: '',
keepalive: false,
isReloadNavigation: false,
isHistoryNavigation: false,
signal: [AbortSignal]
}
}
GET / 200 in 142ms
GET /favicon.ico?favicon.45db1c09.ico 200 in 23ms
It's worthy noting that there are Authorization header in the error log but when capturing requests with Wireshark, the headers are actually missing
I also created a repo shows it works well with client component https://github.com/DebugNinjaSlayer/client-component-demo
Expected Behavior
Given these observations, I'm wondering if there's something I might be misunderstanding about how to use the Strapi JS library within Next.js Server Components.
Is it expected to work correctly in this environment?
Or could this behavior point to a potential incompatibility or bug within the library itself when used in Server Components?
Any guidance on proper usage or confirmation regarding expected compatibility would be incredibly helpful. Thank you!
Version
1.0.0
Operating System
MacOS
Runtime Environment
Node.js
Logs
Media
this is what the missing header requests like
and this is the requests sent from client components or typescript script
Confirmation Checklist
- I have checked the existing issues
- I agree to follow this project's Code of Conduct
- I would like to work on this issue

