[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…