Authentication Middleware and REST: won't render 'unauthenticated' landing page

[Solved. See response below]

My Goal

I’m writing a small REST API (Cake 4.x). It handles one table, stands alone at its own domain, an uses the Authentication Plugin Middleware (Token Authentication).

The Problem

When I make an API call to the site from another Cake app, the basic behavior is good; I get data back and in the format I request.

If I make a call with bad credentials, the response body comes back empty.

I can hand enter URLs in the browser to verify it is working properly. In particular, I can prove the unauthenticatedRedirect configuration for the site is properly working.

Intial Setup

My first approach to the unauthenticatedRedirect page was to include the controller in my REST routes so I could simply get back the same data type that a successful call would deliver.

//in routes.php
$routes->scope('/', function (RouteBuilder $routes) {
    $routes->setExtensions(['xml', 'json']);
    $routes->resources('Inventories');
    $routes->resources('Unauthenticated');
});

//In Application.php
$service = new AuthenticationService([
    'unauthenticatedRedirect' => Router::url('/unauthenticated.json'),
]);

As I said, this setup can be proven to work with a little debugging and direct, hand-entered calls in a browser.

Initial Result

When I make the API call from my other Cake app, the response shows:

debug($response->getStatusCode());
// (int) 302

debug($response->getHeader('location'));
// [
//    (int) 0 => '/unauthenticated.json',
// ]

debug($response->getHeader('content-type'));
// [
//    (int) 0 => 'text/html; charset=UTF-8',
// ]

dd($response->getStringBody());
""

Second approach

Since the content-type doesn’t match the response I’m expecting, I figured the system was just filtering out the mismatched body.

I’m not sure how to change the content-type of the response yet so I changed my unautenticatedRedirect to:

$service = new AuthenticationService([
    'unauthenticatedRedirect' => Router::url('/unauthenticated/test'),
]);

And rendered a simple html response to see if that would work.

Still an empty response body.

Third attempt

This had me wondering if the page truly was being called and rendered. So I put a Cache::write() into the method to verify that it was being run.

It is not!

    public function test()
    {
        Cache::write('failure1', 'access denied');

        $data = [
            'errors' => 'true',
            'message' => 'You cannot be authenticated.',
            'data' => 'none'
        ];
        $this->set(compact('data'));
// I also tried writing my own json response without REST routing
//        $this->viewBuilder()->setLayout('ajax');
    }

I’m at a bit of a loss.

Additional information

I went back to the code in the system that makes the API call and tried something different. I made a call directly to the ‘unauthorized’ handler page with a bad token:

$http = new Client([
   'host' => 'dev.mydomain.com/',
]);
$response = $http->get(
   "unauthenticated.$type",
//   "inventories.$type",
   [
      'token' => 'ba48e2b2-3aed-3cdf-b482-bb6805e335b0xvv',
      'ids' => implode('-', range(4,6)),
   ]
);

This gets me a proper response with the expected body.

Because the page is set to bypass authentication:

//in the Unauthenticated controller intiialize()
$this->Authentication->allowUnauthenticated(['test']);

it is bypassing the failed token check and redirect process. So there seems to be something wrong in that redirect…

I figured out what was happening.

The Authentication Middleware unauthenticatedRedirect as not going to my REST application. It was being sent all the way back to the calling application.

The Http\Client class that makes the API call has a redirect setting (defaults to false).

$http = new Client([
   'host' => 'dev.ampfginv.com/',
   'redirect' => 1
]);

Allows the Middleware on the REST side to run it’s unauthenticated handler method.