I am developing an API using CakePHP 3 framework. Now I'm sending a GET request from POSTMAN client. User will pass an API key in the header.
I wanna fetch this header in my controller function.
This is how my controller looks like
namespace Api\Controller;
use Cake\Auth\DefaultPasswordHasher;
use Api\Controller\AppController;
use Cake\Cache\Cache;
use Cake\Http\ServerRequest;
class ApiController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
public function myinfo()
{
if($this->request->is('get')) {
$key = $this->request->getHeaderLine('Authorization');
$this->set('key', $key);
}
$this->set('_serialize', ['key']);
}
}
The error that I'm getting is: HeaderLine is not a function
I also tried some more options:
$acceptHeader = $this->request->getHeader('Authorization');
but this also threw similar error. Header is not a function.
Reference: Link
CakePHP version: 3.3.5
As #ndm said in the OP comments, the last example in the linked doc should solve your problem. You are using a version prior to 3.4 so you have to use:
// Prior to 3.4.0
$key = $this->request->header('Authorization');
Refere document for Reading HTTP Header
Here mentioned that "Allows you to access any of the HTTP_* headers that were used for the request". Means it reads only http headers like
HTTP Request
Host
Connection
Upgrade-Insecure-Requests
User-Agent
Accept
Accept-Encoding
Accept-Language
Also mentioned that "While some apache installs don’t make the Authorization header accessible, CakePHP will make it available through apache specific methods as required."
So For Solution
They all have different obscure settings you can tweak to overrule this behaviour, but you'll need to determine exactly which module is to blame.
You can work around this issue by passing the header directly to PHP via the env:
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
Also Refere: Zend Server Windows - Authorization header is not passed to PHP script
Related
Hi i'm pretty new on create endpoints in php.
Now i have to create a little endpoint to intercept some updates from electronic invoice service.
From admin panel of the service i can specify endpoint url where my application is located.
For example I indicate: www.example.com/api/endpoint/index.php
NOte: If I set only www.example.com/api/endpoint/, panel admin tell me there is an error - page not found
Now in the admin panel I see I can intercept these POST methods:
/createInvoice
/createNotification
But i don't undertand HOW to differentiate there 2 methods...
Actually in my index.php i've:
<?php
function call_create_invoice(
...
);
function call_create_notification(
...
);
header('Content-Type: application/json; charset=utf-8');
var_dump($_POST);
If I use POSTMAN to do some test using POST call, i can correctly see $_POST parameters sent.... but i don't understand how to:
call call_create_invoice function if /createInvoice is called
call call_create_notification function if /createNotification is called
If you would stick to vanilla PHP, you need to parse the request URI to call the desired function like:
$path = $SERVER['REQUEST_URI'];
switch($path) {
case('/createInvoice'):
call_create_invoice();
break;
case('/createNotification'):
call_create_notification();
break;
}
As requirements grow, it may make sense to use a minimal PHP framework with routing functionality, such as Laravel Lumen.
I want to send a request with or without 'Token' as a header.
If request has 'Token' as a header: if the user already has that item, it will return the item with the proper item_id of a specific user (based on its token), otherwise it will return null.
If request doesn't have 'Token' as a header: it will return the item with that item_id
I'm working with Zend Framework and in ItemResource I have this method:
public function fetch($id)
{
}
How can I check if my request has Token as a header or not and implement both cases inside fetch()?
Using Laminas API Tools it depends on wether you 're using a RPC or a REST resource. I will explain which tools the Laminas API Tools give you to evaluate the received header data.
You don 't have to reinvent the wheel, because Laminas API Tools has the received headers already at hand, when you 're in your fetch method.
Representational State Transfer (REST)
Rest resources normally extend the \Laminas\ApiTools\Rest\AbstractResourceListener class. This class listens for \Laminas\ApiTools\Rest\ResourceEvent. Fortunately, this event provides you with a request object that also contains the received header data.
<?php
declare(strict_types=1);
namespace Marcel\V1\Rest\Example;
use Laminas\ApiTools\Rest\AbstractResourceListener;
class ExampleResource extends AbstractResourceListener
{
public function fetch($id)
{
// requesting for an authorization header
$token = $this->getEvent()->getRequest()->getHeader('Authorization', null);
if ($token === null) {
// header was not received
}
}
}
As you can see the ResourceEvent returns a \Laminas\Http\Request instance when calling getRequest(). The request instance already contains all request headers you 've received. Just call getHeader with the given name and as second parameter a default value, which should be returned, when the header was not set. If there is no http_token header, you 'll get null as a result.
Remote Procedure Calls (RPC)
Since RPC requests are handled with a MVC controller class, you can get the request as easy as in a rest resource. Controller classes extend from \Laminas\Mvc\Controller\AbstractActionController, which already contains a request instance.
<?php
declare(strict_types=1);
namespace Marcel\V1\Rpc\Example;
use Laminas\Mvc\Controller\AbstractActionController;
class ExampleController extends AbstractActionController
{
public function exampleAction()
{
$token = $this->getRequest()->getHeader('Authorization', null);
if ($token === null) {
// token was not set
}
}
}
As you can see getting header data in rpc requests is as easy as in resource listeners. The procedure is the same because a request instance is also used here.
Conclusion
There is absolutely no need for coding things, that are already there. Just get the request instance from the event or the abstract controller and retrieve the header you want. Always keep in mind, that there are security aspects like CRLF injections, when dealing with raw data. The Laminas framework handles all this for you already.
Additionally you can check for all received headers by calling ->getHeaders() instead of ->getHeader($name, $default). You 'll get a \Laminas\Http\Header instance with all received headers.
You can get all HTTP header values by getallheaders() or just get the specific value by $_SERVER['HTTP_XXX'], in your case, replace XXX with Token, $_SERVER['HTTP_Token'].
Manual: https://www.php.net/manual/en/reserved.variables.server.php
public function fetch($id)
{
$token = $_SERVER['HTTP_Token'];
// do your busniess code
}
I am using symfony's HttpClientInterface to make a request to an API.
I know that my base uri will never change and I would like to configure it in /config/packages/framework.yml
Yet whenever I try to set the base_uri, symfony tells me that it is not an available option for http_client.
So, I have reasoned that it most likely must be an option of "scoped_clients" yet whenever I try the code below, Symfony tells me I am missing a base_uri and host or scheme.
http_client:
max_host_connections: 10
scoped_clients:
base_uri: '%app.api.coolapp.base_uri%'
default_options:
headers: { 'X-Powered-By': 'my App' }
max_redirects: 7
So, I think I am missing the concept of the scoped client, because obviously it needs more information or something to get my request url correct. What am I missing?
Thats correct behaviour. Symfony needs a named client for that:
http_client
scoped_clients:
your_api.client: # <-- your configuration's missing this line
base_uri: '%app.api.coolapp.base_uri%'
# ...
I have set-up Laravel using passport as per the documentation here: https://laravel.com/docs/5.3/passport
A few people have asked about this using the oAuth implementation but I'm trying to use the personal access tokens not oAuth. One suggestion was to remove the auth middleware but obviously this leaves the application wide open so anyone can make requests.
I have the following route (in routes/api.php):
Route::get('/test', function(){
return 'returned string from test route';
})->middleware('auth:api');
This works if I remove the auth middleware so the route is working correctly but when enabling the auth middleware again I get the following error in postman:
{"error":"Unauthenticated."}
These are the headers being sent via postman:
GET /api/test HTTP/1.1
Host: localhost:8000
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImU4ZmY5MDMwY2EyM2E2MDYwODViN2Y3ZWNiMzcxNDY1MzQxNDViNTk4ODU4NmZhNDljYzU2YjMzYWZiNzhkYTk5OTIwZWMzYzEwNTBkNjZjIn0.eyJhdWQiOiIyIiwianRpIjoiZThmZjkwMzBjYTIzYTYwNjA4NWI3ZjdlY2IzNzE0NjUzNDE0NWI1OTg4NTg2ZmE0OWNjNTZiMzNhZmI3OGRhOTk5MjBlYzNjMTA1MGQ2NmMiLCJpYXQiOjE0NzU1MDMxNjUsIm5iZiI6MTQ3NTUwMzE2NSwiZXhwIjowLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.IpzKK29dJCpliUXQvPRss87kGFngFcXXwV3jRwhbZOZLxl-4UV70cBsSigmqUuBsHQ4onVl_Cjcq6cEmMFvTZZr7D9AtY3EmScvMPjoFh4KQ3wgd5CoyWfcLQgoBxbElNxL0xW2fIQhpeQd_8Yz_Pr5BByGVTpxfg4JJZ4PzovvZsa2R3izYtqw6-qeurQOtsfOnot5uoLDeDDc76klifnfHfOcNZSoIFGNP3gIGKYBe6lfFuDViR_mQkwQS5_UmERt3GSkEvJjGMtwcRjWY7VPAJ4tvWLnyLw0roGU2e37L0wsqfJ8OrG0Cipv-anXAW_utSo-fiVMr8ZeAWIPguq73Zd44x95YY3nNPOKD5dVIRZM7rQgdhjIwTEz1ggtSXLp-Fu3QOtXaHUahCHvjOTdiTYEa-GR4TZ5wGzt-aRhjdBB7WTe0C6T9ZWVwQr0kJk8AxW6ne87wwJYp_shGunTclZ3SCq5VYg2K_MclbJl65-dT8x-nwqg0lqfNx9s1wmtryrMFIPoBEyaGNEK1aWGHKq418-BIQ1_UAhcHHtEXclWvsGWwhyo3aso-E-sCN2o_IkYvSboIsdFAIXvDvQmoAwis6f1J57zWH8AW1ynCFcBgzBDjIyiaCE5nqtb_4zbEXr8L1EbcllbtZkq3vd9w996kO7xlpBEWwPY8IWg
Accept: application/json
Cache-Control: no-cache
Postman-Token: 6bc483b2-23df-acce-7eef-5a443f8f5d45
Firstly, NEVER modify the vendor files unless you have a fully legitimate reason for doing so and there's a feature you wish to see implemented or a bug you've discovered and fixed in the package you're using.
Expiration time on the JWT might be already set to expire as soon as it's made. Here's a link you can use to check the "ttl" (Time To Live) field of your access tokens:
https://jwt.io/
If you find that your tokens are expiring on creation, you can go to your app\providers\AuthServiceProvider.php class and add in these methods on use of Passport Class:
use Carbon\Carbon;
use Laravel\Passport\Passport;
...
Class AuthServiceProvider extends ServiceProvider {
...
...
public function boot() {
$this->registerPolicies();
Passport::routes();
Passport::tokensExpireIn(Carbon::now()->addYears(20));//You can also use addDays(10)
Passport::refreshTokensExpireIn(Carbon::now()->addYears(20));//You can also use addDays(10)
Passport::pruneRevokedTokens(); //basic garbage collector
}
}
Make sure you're using the most recent version of Passport
Currently I'm on version 1.0.8 but I might already be out of date as they and the community are constantly pushing new revisions every few weeks.
Here are links to some related issues regarding this problem. You might be able to locate your answer within one of the below links. If what's mentioned above isn't what you're looking for.
Passport - "Unauthenticated." - Laravel 5.3
Very Detailed
https://github.com/laravel/passport/issues/151
in passport.php there are two functions
public static function tokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$tokensExpireAt
? Carbon::now()->diff(static::$tokensExpireAt)
: new DateInterval('P100Y');
} else {
static::$tokensExpireAt = $date;
}
return new static;
}
/**
* Get or set when refresh tokens expire.
*
* #param \DateTimeInterface|null $date
* #return \DateInterval|static
*/
public static function refreshTokensExpireIn(DateTimeInterface $date = null)
{
if (is_null($date)) {
return static::$refreshTokensExpireAt
? Carbon::now()->diff(static::$refreshTokensExpireAt)
: new DateInterval('P100Y');
} else {
static::$refreshTokensExpireAt = $date;
}
return new static;
}
you must change P100Y to P1Y. and also in PassportserviceProvider.php at line 101 there is code
$server->enableGrantType(
new PersonalAccessGrant, new DateInterval('P100Y')
);
change P100Y to P1Y. hope it helps you :)
Please check if the token was copied properly, i always observed when i copy the personal tokens, in the last there is a word 'Close' copied also.
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImU4ZmY5MDMwY2EyM2E2MDYwODViN2Y3ZWNiMzcxNDY1MzQxNDViNTk4ODU4NmZhNDljYzU2YjMzYWZiNzhkYTk5OTIwZWMzYzEwNTBkNjZjIn0.eyJhdWQiOiIyIiwianRpIjoiZThmZjkwMzBjYTIzYTYwNjA4NWI3ZjdlY2IzNzE0NjUzNDE0NWI1OTg4NTg2ZmE0OWNjNTZiMzNhZmI3OGRhOTk5MjBlYzNjMTA1MGQ2NmMiLCJpYXQiOjE0NzU1MDMxNjUsIm5iZiI6MTQ3NTUwMzE2NSwiZXhwIjowLCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.IpzKK29dJCpliUXQvPRss87kGFngFcXXwV3jRwhbZOZLxl-4UV70cBsSigmqUuBsHQ4onVl_Cjcq6cEmMFvTZZr7D9AtY3EmScvMPjoFh4KQ3wgd5CoyWfcLQgoBxbElNxL0xW2fIQhpeQd_8Yz_Pr5BByGVTpxfg4JJZ4PzovvZsa2R3izYtqw6-qeurQOtsfOnot5uoLDeDDc76klifnfHfOcNZSoIFGNP3gIGKYBe6lfFuDViR_mQkwQS5_UmERt3GSkEvJjGMtwcRjWY7VPAJ4tvWLnyLw0roGU2e37L0wsqfJ8OrG0Cipv-anXAW_utSo-fiVMr8ZeAWIPguq73Zd44x95YY3nNPOKD5dVIRZM7rQgdhjIwTEz1ggtSXLp-Fu3QOtXaHUahCHvjOTdiTYEa-GR4TZ5wGzt-aRhjdBB7WTe0C6T9ZWVwQr0kJk8AxW6ne87wwJYp_shGunTclZ3SCq5VYg2K_MclbJl65-dT8x-nwqg0lqfNx9s1wmtryrMFIPoBEyaGNEK1aWGHKq418-BIQ1_UAhcHHtEXclWvsGWwhyo3aso-E-sCN2o_IkYvSboIsdFAIXvDvQmoAwis6f1J57zWH8AW1ynCFcBgzBDjIyiaCE5nqtb_4zbEXr8L1EbcllbtZkq3vd9w996kO7xlpBEWwPY8IWg Copy
If this is not your case check if that token exist, or generate a new one. you can use this format to protect route like this
Route::middleware('auth:api')->get('/home', function(){
return 'test';
});
I Had this problem ... two hours down the pan. Something very strange was happening and in my case I think Postman was the culprit.
Inspect the received header to rule it out:
Route::get('/test', function(){
dd( Request::header());
})/*->middleware('auth:api')*/; //disable auth middleware to inspect header
this is the strange thing I found:
.........
"authorization" => array:1 [
0 => b"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ ................
what the hell was the 'b' before Bearer ACCESS_TOKEN ???
I typed it out again and it dissapeared and auth middleware started working.
Inspect the header exactly and then add the middleware back. This might just be the cause!
Long story short:
I'm building a skeleton application for Zend Framework and I got to the part where I need to setup the api module. I'm using Zend_Rest_Controller for this job. All is ok up to this part where I need to get the HTTP headers in a controller to verify the api key.
On various tutorials I've read on the web the thing is done via a front controller plugin, but I need it to be more "plug and play" than that (checking each time the config of the application, deciding which module is the api and so on).
I tried what seemed most obvious $this->getRequest()->getHeaders() but doesn't seem to work, at least not for the HTTP headers where I'll be seding my api key. Neither the reponse object.
Can anyone help me with this one?
I found a way of doing this after all :)
On the preDispatch() method in your controller you can do the following:
public function preDispatch()
{
$request = new Zend_Controller_Request_Http();
$key = $request->getHeader('x-apikey');
}
It seems that Zend_Controller_Request_Http object gives you acces to the headers. More info on the Zend_Controller_Request_Http you can find here
As Bogdan said, you can find that information in the Zend_Controller_Request_HTTP class. It can be found in the controller itself by doing :
$this -> getFrontController() -> getRequest() -> getHeader('Content-Type');
Unfortunatly, you can't access all headers at once but what ZF does is just use apache_request_headers() function if available on the server to get them.