I'm using Laravel 9, and using the HTTP Client (GuzzleHTTP) to make calls to an API. Previously this just worked, however the last few days something has changed (On their end, I believe) and my requests are having the authorization header stripped - whether I use withHeaders() or withToken().
Here's the relevant code:
private function buildRequest($options = []): PendingRequest { $request = Http:: // withToken($this->accessToken ?? $this->getAccessToken()) // <- this doesn't work either withHeaders([ 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $this->accessToken ?? $this->getAccessToken() ])->baseUrl($this->baseUrl) ->timeout($this->timeout) ->withOptions($options); if (!is_null($this->retryTimes) && !is_null($this->retryMilliseconds)) { $request->retry($this->retryTimes, $this->retryMilliseconds); } return $request; }
The first request works, however when I try to request the second page (Using the below options) the request object has the authorization header completely stripped.
array:2 [ "limit" => "100" "page" => "2" ]
Request object:
-request: GuzzleHttp\Psr7\Request {#969
-method: "GET"
-requestTarget: null
-uri: GuzzleHttp\Psr7\Uri {#984
-scheme: "https"
-userInfo: ""
-host: "api.APIPLACE.io"
-port: null
-path: "/v4/stuff"
-query: "limit=100?page=2"
-fragment: ""
-composedComponents: "https://api.APIPLACE.io/v4/stuff?limit=100?page=2"
}
-headers: array:4 [
"Host" => array:1 [
0 => "api4.APIPLACE.io"
]
"User-Agent" => array:1 [
0 => "GuzzleHttp/7"
]
"Accept" => array:1 [
0 => "application/json"
]
"Content-Type" => array:1 [
0 => "application/json"
]
]
-headerNames: array:4 [
"host" => "Host"
"user-agent" => "User-Agent"
"accept" => "Accept"
"content-type" => "Content-Type"
]
What's going on? Why is the bearer token being stripped from the request? Obviously the response from the API Is:
access_denied: Must define bearer access token in header or request.
Some more code (The code to make multiple requests depending on how many pages there are):
private function getAllPages($response, $options) {
$return = array();
$links = $this->returnHeaderArray($response->headers());
try {
while (@isset($links) && @isset($links['next']) && !$response->failed()) {
$this->checkToken();
$options = array_merge($options, $links['next_page_options']);
$request = $this->buildRequest($options);
$response = $request->get($links['next']);
dump($response, $options, $request);
$links = $this->returnHeaderArray($response->headers(), $links['total']);
if ($response->successful())
$return = array_merge($return, $response->json());
}
} catch (\Exception $e) {
dd($e);
return $return;
}
return $return;
}
I figured it out - the API changed their response for 'next' and 'last' pages to http:// instead of https://, and guzzle strips the Authorization header when there's a redirect - which there was a redirect because the API's servers have one set to redirect all http to https.
I know it's an edge case but hopefully this will help someone in the future.
Always make sure to add dump() to your requests if you're having issues with the authorization header being stripped, and if you see redirects or http:// when your initial URL was https... Well, that's the issue. I fixed it by just searching for http:// and replacing it with https:// before calling the 'Next' page.