5

My Guzzle POST request to https://api.scarif.dev/auth gives back a 404, while the page exists through Postman, or browser, or javascript. It should return a 200 with a 401 message, but Guzzle gives back a 404. In both POST and GET mode that is.

I've tried multiple Client setups, including different headers and disabling SSL verification, but without any success. Now I've copied the exact same headers that made it work in postman, but still no success.

I've been searching through google and stackoverflow, but couldn't find an answer that fixed my problem.

Request in PHP:

<?php
$client = new Client([
    'header' => [
        'Accept' => 'application/json',
        'Content-Type' => 'application/x-www-form-urlencoded'
    ],
    'verify' => false
]);

$response = $client->request('POST', 'https://api.scarif.dev/auth', [
    'form_params' => []
]);

echo $response->getBody()->getContents();
?>

Expected result:

{
    "detail": "https://login.scarif.dev",
    "status": 401,
    "title": "Unauthorized",
    "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"
}

Actual result:

Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: POST https://api.scarif.dev/auth resulted in a 404 Not Found response: 404 Not Found

Not Found (truncated...) in /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113 Stack trace: #0 /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response)) 2 /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/promises/src/Promise.php(156):

GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array) #3 /home/admin/domains/login.scarif.dev/framework/ven in /home/admin/domains/login.scarif.dev/framework/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113

API endpoint controller:

<?php

namespace Controller;

use Core\Config;
use Core\Request;
use Core\Response;
use Model\Token;
use Model\User;
use MongoDB\BSON\UTCDateTime;

class AuthController extends Controller
{
    public function view(User $user, Token $token)
    {
        extract(Request::getPostData());

        if (isset($access_token) && !empty($access_token)) {
            $_token = $token->getTokenByToken($access_token);

            if (
                $_token['type'] !== Token::TYPE_ACCESS_TOKEN ||
                $_token['expires_on'] <= new UTCDateTime()
            ) {
                return $this->view->display('json', [
                    'payload' => Response::apiResponse(
                        $this->config->get('url.login'), 401
                    )
                ]);
            }

            $token->delete($_token['_id']);

            $newToken = $token->create(Token::TYPE_ACCESS_TOKEN, $_token['user_id']);

            return $this->view->display('json', [
                'payload' => Response::apiResponse($newToken['token'])
            ]);
        }

        if (!isset($email) || !isset($password) || empty($email) || empty($password)) {
            return $this->view->display('json', [
                'payload' => Response::apiResponse(
                    $this->config->get('url.login'), 401
                )
            ]);
        }

        if (!$user->checkCredentials($email, $password)) {
            return $this->view->display('json', [
                'payload' => Response::apiResponse(
                    "The email address or password you've entered is invalid. Please check your entry and try again.",
                    422
                )
            ]);
        }

        $user = $user->getUserByEmail($email);
        $token = $token->create(Token::TYPE_ACCESS_TOKEN, $user['_id']);

        return $this->view->display('json', [
            'payload' => Response::apiResponse($token['token'])
        ]);
    }
}

2 Answers2

0

It seems like the issue is coming from the API you are consuming. When using your code with a different url it works just fine:

$client = new Client([
    'header' => [
        'Accept' => 'application/json',
        'Content-Type' => 'application/x-www-form-urlencoded'
    ],
    'verify' => false
]);

$response = $client->request('POST', 'https://jsonplaceholder.typicode.com/posts', [
    'form_params' => []
]);

echo $response->getBody()->getContents();

Could you show the code for the API endpoints?

PtrTon
  • 3,705
  • 2
  • 14
  • 24
  • From what I can see your API does not return a 404 in any case, which means your request probably doesn't even make it to the controller. Have you tried returning a simple response to see if the controller action is even called? – PtrTon Apr 20 '19 at 11:50
  • Oke this is very weird, I think it's my server settings. If I point to https://api.scarif.dev, it should give back a string saying "Welcome to Scarif API", yet it returns "Apache is functioning normally". –  Apr 20 '19 at 12:00
  • Everything seems to be fine. How can it be that Guzzle acts different then any other client I'm using? Is there a way to check what the actual url is that guzzle ends up with? To see if there are any redirects active or what so ever? There aren't any in my code. –  Apr 20 '19 at 12:25
  • Consider logging what Guzzle does exactly. Something like [this](https://stackoverflow.com/questions/32681165/how-do-you-log-all-api-calls-using-guzzle-6) should help figure that out. – PtrTon Apr 20 '19 at 12:30
  • Hmm it looks like my SSL wildcard doesn't work properly. It's been setup on scarif.dev through DirectAdmin, yet I've added api.scarif.dev and login.scarif.dev as seperate domains, installed the same certificates on them, but they come back as self-signed certificates, while my browser says different. Interesting :/ –  Apr 20 '19 at 12:35
  • So when i run the EXACT same code from my local machine and post to the API on the live server, it works. Why can't i make requests between the two url's, both on the same server. I don't get access errors, everything seem to be oke, setup, settings, yet i cannot make the call online. –  Apr 20 '19 at 13:10
  • I approached it from a different angle, so didn't fixed it unfortunately. Thanks for the help though! –  Apr 21 '19 at 13:25
0

I had the same issue and was looking for solutions until I landed here. Didn't get any help online though and solutions of other people didn't work for me but later I solved myself through extensive debugging and I am sharing the solution in a hope it might help someone else in the future.

Scenario: In my case I had an API gateway and client (Postman in my case) was making request to the API gateway and gateway in turn was making request to a microservice using Guzzle 7 in Laravel 8. I used to pass all headers I received from the client to microservice as is and that was causing 404 error. When I changed that and passed only my own headers in the request to the microservice, there was light and 404 was gone.

These were default headers of Postman and I was passing in the request as is:

{
    "authorization": [
        "Bearer eyJ0eXAiOiJKV1 .."
    ],
    "user-agent": [
        "PostmanRuntime/7.29.0"
    ],
    "accept": [
        "*/*"
    ],
    "postman-token": [
        "ca180f3a-ec65-4212-bd9f-dc294846dc65"
    ],
    "host": [
        "sagateway.com"
    ],
    "accept-encoding": [
        "gzip, deflate, br"
    ],
    "connection": [
        "keep-alive"
    ]
}

I removed all of it and only passed one thing in the header:

['Authorization' => "<Key Here>"]

It then worked fine and I took a breath of relief after a few days of continuous googling.

Ismail
  • 331
  • 3
  • 10