Getting 404 when expecting 401
A short story about the mysterious behavior of an API in headless architecture.

There is a noticeable wind of change in my experience with Optimizely projects. I am more involved in projects with headless architecture (PaaS CMS with REST API and Graph + FE app), which is new for me. It brings excitement and new challenges.
One of them is quite an unusual issue I was experiencing. Everything is set up, and the API works fine, except for one small detail. When accessing a secure endpoint while being unauthorized, the API returns a 404 HTTP code instead of 401. And it happens only on DXP. The local environment is fine.
Hours or even days of double-checking site setup, middleware, and auth configuration yielded no clues. I almost gave up, but finally, I found a reason.
Apparently, the CMS UI, when initialized, adds StatusCodePagesMiddleware for environments other than development. Everything is happening in the process of AddCms() → AddCmsUi(), which registers ErrorsStartupFilter. This is checking the environment and adding middleware to the pipeline. So what is it doing then? When there is an HTTP result other than 200, it will try to find the HTML page for a specific status code, 401 in this case. What if there is no such a page? It returns 404.

What is a workaround for it? Middleware just needs to be told when it shouldn’t make this operation. How? Simply by adding the [SkipStatusCodePages] attribute to our API controller. Problem solved, now 401 is successfully returned when needed.
More articles

Exposing Color Picker to Content Graph
A guide on how to consume custom CMS property backing types in a headless architecture, using a color picker as an example.

Decimal numbers in Optimizely Graph
Storing prices as decimal numbers on a commerce website and planning to expose them through Optimizely Graph? It might not be as straightforward as it seems.

Optimizely SaaS CMS + Coveo Search Page
Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data from the Optimizely SaaS CMS - all during just a break between coffee refills.