Error ghost/api/admin/settings/ 403 (Forbidden)

Hi

  • I am running ghost 5.105.0
  • Just did a reinstallation for ghost. Complete fresh install. Had same issues before reinstall, came after an upgrade some time ago
  • Node v18.20.4
  • URL: Evetro

The blog is up and running, ghost doctor checks that everything is fine. Nginx config looks good.

But on the settings site in ghost (I have owner rights / admin btw) i get these error in console:

PUT https://www.evetro.com/blog/ghost/api/admin/settings/ 403 (Forbidden)

Xr: Something went wrong while loading settings, please try again.
    at pk (https://www.evetro.com/blog/ghost/assets/admin-x-settings/index-ddcccc3d.mjs:19578:575)

modals-bdac35ab.mjs:17148 Uncaught (in promise) Xr: Something went wrong while loading settings, please try again.
    at pk (https://www.evetro.com/blog/ghost/assets/admin-x-settings/index-ddcccc3d.mjs:19578:575)

This happens when i try to change settings like the navigation bar. Also cover photos, logos etc. don’t get uploaded even if I am able to save that settings page after trying to upload images.

My blog page headers have missing image icons on default images like: https://casper.ghost.org/v1.0.0/images/ghost-logo.svg

What is causing these issues and how do i fix them?

A 403 would suggest that you don’t have permissions to do what you’re requesting, so it might be worth logging out and back in, just to confirm you’ve got a good cookie.

Can you take a look in your ghost logs also? They should be in <ghostdir>/settings/logs

Logging out and back in did not fix anything:

Here is the newest error logs:

{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","req":{"meta":{"requestId":"ccc5f1ed-70ca-4c12-a893-4b95c6ab5bf2","userId":"1"},"url":"/settings/","method":"PUT","originalUrl":"/blog/ghost/api/admin/settings/","params":{},"headers":{"x-forwarded-for":"109.108.211.181","host":"www.evetro.com","x-forwarded-proto":"https","connection":"close","content-length":"97","x-ghost-version":"5.105","sec-ch-ua-platform":"\"Windows\"","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","sec-ch-ua":"\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"","content-type":"application/json","app-pragma":"no-cache","sec-ch-ua-mobile":"?0","accept":"*/*","origin":"https://www.evetro.com","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://www.evetro.com/blog/ghost/","accept-encoding":"gzip, deflate, br, zstd","accept-language":"nb-NO,nb;q=0.9,no;q=0.8,nn;q=0.7,en-US;q=0.6,en;q=0.5","cookie":"**REDACTED**"},"query":{}},"res":{"_headers":{"x-powered-by":"Express","content-version":"v5.105","vary":"Accept-Version, Accept-Encoding","cache-control":"no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0","content-type":"application/json; charset=utf-8","content-length":"280","etag":"W/\"118-Drnu2HaSDj0AlELjGXstzwuLXvE\""},"statusCode":403,"responseTime":"30ms"},"err":{"id":"376f8760-cdb7-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"NoPermissionError","statusCode":403,"level":"normal","message":"Attempted to access core setting from external request","stack":"NoPermissionError: Attempted to access core setting from external request\n    at SettingsBREADService.edit (/opt/ghost/versions/5.105.0/core/server/services/settings/SettingsBREADService.js:190:23)\n    at Object.query (/opt/ghost/versions/5.105.0/core/server/api/endpoints/settings.js:136:53)\n    at async getResponse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:259:34)\n    at async ImplWrapper (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:264:30)\n    at async Http (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/http.js:70:28)","hideStack":false},"msg":"Attempted to access core setting from external request","time":"2025-01-08T11:53:46.461Z","v":0}
{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","err":{"id":"9c5a2a10-cdc9-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"BadRequestError","statusCode":400,"level":"normal","message":"Error parsing filter","stack":"Error: Query Error: unexpected character in filter at char 7\n    at Child.applyDefaultAndCustomFilters (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:68:23)\n(tags:[]+id:-670d0c49f03cc1\n-------^\nExpecting 'NULL', 'TRUE', 'FALSE', 'NUMBER', 'NOW', 'LITERAL', 'STRING', got 'RBRACKET'\n    at parser.parseError (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/dist/parser.js:359:12)\n    at Parser.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/dist/parser.js:276:22)\n    at exports.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/lib/nql.js:18:44)\n    at api.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/node_modules/@tryghost/nql/lib/nql.js:33:31)\n    at api.querySQL (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/node_modules/@tryghost/nql/lib/nql.js:77:44)\n    at Builder.<anonymous> (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:65:24)\n    at Object.query (/opt/ghost/versions/5.105.0/node_modules/bookshelf/lib/helpers.js:164:14)\n    at Child.query (/opt/ghost/versions/5.105.0/node_modules/bookshelf/lib/model.js:1387:22)\n    at Child.applyDefaultAndCustomFilters (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:57:22)\n    at Function.getFilteredCollection (/opt/ghost/versions/5.105.0/core/server/models/base/plugins/filtered-collection.js:13:32)\n    at Function.findPage (/opt/ghost/versions/5.105.0/core/server/models/base/plugins/crud.js:83:41)\n    at PostsService.browsePosts (/opt/ghost/versions/5.105.0/node_modules/@tryghost/posts-service/lib/PostsService.js:82:44)\n    at Object.query (/opt/ghost/versions/5.105.0/core/server/api/endpoints/posts-public.js:116:33)\n    at Object.query (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:159:24)\n    at getResponse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:259:47)\n    at async Object.ImplWrapper [as browse] (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:264:30)","hideStack":false},"msg":"Error parsing filter","time":"2025-01-08T14:05:26.707Z","v":0}
{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","err":{"id":"a0e864c0-cdc9-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"BadRequestError","statusCode":400,"level":"normal","message":"Error parsing filter","stack":"Error: Query Error: unexpected character in filter at char 7\n    at Child.applyDefaultAndCustomFilters (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:68:23)\n(tags:[]+id:-65353aab5787f0\n-------^\nExpecting 'NULL', 'TRUE', 'FALSE', 'NUMBER', 'NOW', 'LITERAL', 'STRING', got 'RBRACKET'\n    at parser.parseError (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/dist/parser.js:359:12)\n    at Parser.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/dist/parser.js:276:22)\n    at exports.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/nql-lang/lib/nql.js:18:44)\n    at api.parse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/node_modules/@tryghost/nql/lib/nql.js:33:31)\n    at api.querySQL (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/node_modules/@tryghost/nql/lib/nql.js:77:44)\n    at Builder.<anonymous> (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:65:24)\n    at Object.query (/opt/ghost/versions/5.105.0/node_modules/bookshelf/lib/helpers.js:164:14)\n    at Child.query (/opt/ghost/versions/5.105.0/node_modules/bookshelf/lib/model.js:1387:22)\n    at Child.applyDefaultAndCustomFilters (/opt/ghost/versions/5.105.0/node_modules/@tryghost/bookshelf-filter/lib/bookshelf-filter.js:57:22)\n    at Function.getFilteredCollection (/opt/ghost/versions/5.105.0/core/server/models/base/plugins/filtered-collection.js:13:32)\n    at Function.findPage (/opt/ghost/versions/5.105.0/core/server/models/base/plugins/crud.js:83:41)\n    at PostsService.browsePosts (/opt/ghost/versions/5.105.0/node_modules/@tryghost/posts-service/lib/PostsService.js:82:44)\n    at Object.query (/opt/ghost/versions/5.105.0/core/server/api/endpoints/posts-public.js:116:33)\n    at Object.query (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:159:24)\n    at getResponse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:259:47)\n    at async Object.ImplWrapper [as browse] (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:264:30)","hideStack":false},"msg":"Error parsing filter","time":"2025-01-08T14:05:34.351Z","v":0}
{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","req":{"meta":{"requestId":"5226b734-2ac2-4f01-b561-1c0cfa0a2c81","userId":null},"url":"/users/me/?include=roles","method":"GET","originalUrl":"/blog/ghost/api/admin/users/me/?include=roles","params":{},"headers":{"x-forwarded-for":"109.108.211.181","host":"www.evetro.com","x-forwarded-proto":"https","connection":"close","x-ghost-version":"5.105","sec-ch-ua-platform":"\"Windows\"","sec-ch-ua":"\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"","app-pragma":"no-cache","sec-ch-ua-mobile":"?0","x-requested-with":"XMLHttpRequest","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","accept":"application/json, text/javascript, */*; q=0.01","content-type":"application/json; charset=UTF-8","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://www.evetro.com/blog/ghost/","accept-encoding":"gzip, deflate, br, zstd","accept-language":"nb-NO,nb;q=0.9,no;q=0.8,nn;q=0.7,en-US;q=0.6,en;q=0.5","cookie":"**REDACTED**"},"query":{"include":"roles"}},"res":{"_headers":{"x-powered-by":"Express","content-version":"v5.105","vary":"Accept-Version, Accept-Encoding","cache-control":"no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0","content-type":"application/json; charset=utf-8","content-length":"343","etag":"W/\"157-tGZUahixvaE0mQab/yl8H3pKTe4\""},"statusCode":403,"responseTime":"9ms"},"err":{"id":"9d0a7c60-cdcb-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"NoPermissionError","statusCode":403,"level":"normal","message":"Authorization failed","context":"\"Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication.\"","stack":"NoPermissionError: Authorization failed\n    at authorizeAdminApi (/opt/ghost/versions/5.105.0/core/server/services/auth/authorize.js:33:25)\n    at Layer.handle [as handle_request] (/opt/ghost/versions/5.105.0/node_modules/express/lib/router/layer.js:95:5)\n    at next (/opt/ghost/versions/5.105.0/node_modules/express/lib/router/route.js:149:13)\n    at authenticate (/opt/ghost/versions/5.105.0/core/server/services/auth/session/middleware.js:54:13)","hideStack":false},"msg":"Authorization failed","time":"2025-01-08T14:19:46.865Z","v":0}
{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","req":{"meta":{"requestId":"9690d2f4-6300-48e9-a108-187ce9b5f024","userId":null},"url":"/users/me/?include=roles","method":"GET","originalUrl":"/blog/ghost/api/admin/users/me/?include=roles","params":{},"headers":{"x-forwarded-for":"109.108.211.181","host":"www.evetro.com","x-forwarded-proto":"https","connection":"close","x-ghost-version":"5.105","sec-ch-ua-platform":"\"Windows\"","sec-ch-ua":"\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"","app-pragma":"no-cache","sec-ch-ua-mobile":"?0","x-requested-with":"XMLHttpRequest","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","accept":"application/json, text/javascript, */*; q=0.01","content-type":"application/json; charset=UTF-8","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://www.evetro.com/blog/ghost/","accept-encoding":"gzip, deflate, br, zstd","accept-language":"nb-NO,nb;q=0.9,no;q=0.8,nn;q=0.7,en-US;q=0.6,en;q=0.5","cookie":"**REDACTED**"},"query":{"include":"roles"}},"res":{"_headers":{"x-powered-by":"Express","content-version":"v5.105","vary":"Accept-Version, Accept-Encoding","cache-control":"no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0","content-type":"application/json; charset=utf-8","content-length":"343","etag":"W/\"157-AYap9UmqLjEcDZDw6hzaVc7lwdw\""},"statusCode":403,"responseTime":"4ms"},"err":{"id":"9d1d4110-cdcb-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"NoPermissionError","statusCode":403,"level":"normal","message":"Authorization failed","context":"\"Unable to determine the authenticated user or integration. Check that cookies are being passed through if using session authentication.\"","stack":"NoPermissionError: Authorization failed\n    at authorizeAdminApi (/opt/ghost/versions/5.105.0/core/server/services/auth/authorize.js:33:25)\n    at Layer.handle [as handle_request] (/opt/ghost/versions/5.105.0/node_modules/express/lib/router/layer.js:95:5)\n    at next (/opt/ghost/versions/5.105.0/node_modules/express/lib/router/route.js:149:13)\n    at authenticate (/opt/ghost/versions/5.105.0/core/server/services/auth/session/middleware.js:54:13)","hideStack":false},"msg":"Authorization failed","time":"2025-01-08T14:19:46.980Z","v":0}
{"name":"Log","hostname":"evetro-app-server-01","pid":97239,"level":50,"version":"5.105.0","req":{"meta":{"requestId":"8c0f89a1-8925-4922-89a1-5f1c79dfd595","userId":"1"},"url":"/settings/","method":"PUT","originalUrl":"/blog/ghost/api/admin/settings/","params":{},"headers":{"x-forwarded-for":"109.108.211.181","host":"www.evetro.com","x-forwarded-proto":"https","connection":"close","content-length":"87","x-ghost-version":"5.105","sec-ch-ua-platform":"\"Windows\"","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36","sec-ch-ua":"\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"","content-type":"application/json","app-pragma":"no-cache","sec-ch-ua-mobile":"?0","accept":"*/*","origin":"https://www.evetro.com","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://www.evetro.com/blog/ghost/","accept-encoding":"gzip, deflate, br, zstd","accept-language":"nb-NO,nb;q=0.9,no;q=0.8,nn;q=0.7,en-US;q=0.6,en;q=0.5","cookie":"**REDACTED**"},"query":{}},"res":{"_headers":{"x-powered-by":"Express","content-version":"v5.105","vary":"Accept-Version, Accept-Encoding","cache-control":"no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0","content-type":"application/json; charset=utf-8","content-length":"280","etag":"W/\"118-stGVFAVeRYqfN1j/vW03WcRopAI\""},"statusCode":403,"responseTime":"20ms"},"err":{"id":"b3b60380-cdcb-11ef-8eef-19e3202d7d6f","domain":"https://evetro.com/blog","code":null,"name":"NoPermissionError","statusCode":403,"level":"normal","message":"Attempted to access core setting from external request","stack":"NoPermissionError: Attempted to access core setting from external request\n    at SettingsBREADService.edit (/opt/ghost/versions/5.105.0/core/server/services/settings/SettingsBREADService.js:190:23)\n    at Object.query (/opt/ghost/versions/5.105.0/core/server/api/endpoints/settings.js:136:53)\n    at async getResponse (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:259:34)\n    at async ImplWrapper (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/pipeline.js:264:30)\n    at async Http (/opt/ghost/versions/5.105.0/node_modules/@tryghost/api-framework/lib/http.js:70:28)","hideStack":false},"msg":"Attempted to access core setting from external request","time":"2025-01-08T14:20:24.892Z","v":0}

OK, some useful bits extracted from that:

First one: (This is your 403)

endpoint: /blog/ghost/api/admin/settings/  (PUT) 
error: NoPermissionError: Attempted to access core setting from external request

^^This is the error related to your problem, but it’s weird, because if you’re working within the admin dashboard, there’s no reason for Ghost to think it’s an external request.

Second one - probably unrelated to current problem.

"Error: Query Error: unexpected character in filter at char 7"

That’s a front-end error, probably not related to this issue. You’ve got somewhere you’re using a variable to pass in tag slugs, but it is empty - the filter resulting is tags:[]+id:-670d0c49f03cc1, which isn’t a valid filter setting. (Check for somewhere you’re making a get request with a filter.)

Third one (ignoring duplicates):
The 403 error for /blog/ghost/api/admin/users/me/?include=roles happens any time you try to access the dashboard while not being logged in. It’s normally unremarkable, but if you thought you were logged in at the time, it might be a symptom of the problem. (It’s also possible that this corresponds to when you logged out and back in, in which case there’s nothing to see here.)

So… something weird is going on here, based on the first error message. Are you running a proxy or anything that might be rewriting your headers in a way that’s causing Ghost not to recognize that the request is from the admin panel?

Hi, no not using a proxy.

Nothing that rewrites headers that I can think of

I did have to write a chmod command during install after running ghost doctor ( suggested by ghost doctor) to fix some read/write access issues

Some sort of privacy/security guard, maybe? Something is causing Ghost to not recognize the PUT requests as internal requests, even though you’re making them from the dashboard. If you have a different browser available, perhaps try it to see if the problem recurs? If you’re working in a corporate/university/firewall-happy location, try from elsewhere (or hook your device up to your phone’s hotspot briefly, if allowed)?

It might also be informative to look at the network calls (fetch/xhr particularly) in the browser console (F12 then network tab) to see if whether all the requests are going to the same domain (all to the dashboard domain, if you have them separated), all either with or without www (not a mix), and all with https.

This is one of those things that’s going to be hard to fix without a reproduction.

The chmod seems unlikely to be the problem…

If i upload an image it seems like it gets uploaded. If i visit the link for the image I can see the direct image, no problem. But I do not get any visual confirmation from the Ghost UI that the publication cover is changed,

If I look at my missing cover image the source says
https://casper.ghost.org/v1.0.0/images/blog-cover.jpg”. But there is no image or page on that link. Why is ghost by default trying to reach a link here that does not work?

and I try to visit that link, there is no page or image there.

Another weird thing I noticed is this warning in the top banner:
" Ghost 2.0 is now end-of-life as of January 2021 - You are using an old version of Ghost, which means you don’t have access to the latest features. Read more about Ghost v5!“”

Even though every version check for Ghost on the server says I am running the latest version.

Other image uploads, like for posts seems to work fine.

It is the images from ghost itself or for themes (cover photos, publication photos etc. that does not work).

Any idea why this might happen?