admad / cakephp-jwt-auth Goto Github PK
View Code? Open in Web Editor NEWA CakePHP plugin for authenticating using JSON Web Tokens
License: MIT License
A CakePHP plugin for authenticating using JSON Web Tokens
License: MIT License
The function getToken() was recently changed and caused an authentication error in my project. I think an incorrect variable was introduced in a recent change when a token is provided as a query param.
Ie. $this->_token was possibly incorrectly replaced by $token
Made the change in my fork to check and test.
I know we should ever encrypt passwords but I just do not understood why it does not work ;)
When I add to my User Entity
use Cake\Auth\DefaultPasswordHasher;
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
every thing works well. But without those lines (I just not encrypt passwords) the authentication does not work. The token is ok.
The word Bearer
used in headers, should be capitalized, based on RFC6750: https://tools.ietf.org/html/rfc6750
Hello, is there a way to do not check the token expiration? So if the token is expired, I want to get logged in correctly.
As the config array get merged (deep):
If you specify allowedAlgs => ['RS256'], you end up with allowedAlgs beeing set to ['HS256', 'RS256'], which is NOT the intended result and causes an attacker to be able to alter the Token and create a good signature with just the public key!
Hello,
I just tried with this, but without success :
$this->loadComponent('Auth', [ 'storage' => 'Memory', 'authenticate' => [ 'Form' => [ 'passwordHasher' => [ 'className' => 'Weak', 'hashers' => [ 'Weak', 'Default', ] ] ], 'ADmad/JwtAuth.Jwt' => [ 'parameter' => 'token', 'userModel' => 'Users', 'fields' => [ 'username' => 'id' ], 'passwordHasher' => [ 'className' => 'Weak', 'hashers' => [ 'Weak', 'Default', ] ], 'queryDatasource' => true ] ], 'unauthorizedRedirect' => false, 'checkAuthIn' => 'Controller.initialize' ]);
Thank You
Running into this problem with 3.6, though things seem to be otherwise working. This is occurring with
public function __construct(ComponentRegistry $registry, $config)
{
$this->setConfig([
'header' => 'authorization',
'prefix' => 'bearer',
'parameter' => 'token',
'queryDatasource' => true,
'fields' => ['username' => 'id'],
'unauthenticatedException' => UnauthorizedException::class,
'key' => null,
]);
if (empty($config['allowedAlgs'])) {
$config['allowedAlgs'] = ['HS256'];
}
parent::__construct($registry, $config);
}
Is there anything I can do to fix this in code?
I am following the "Bravo" tutorial and I have the api method to add a User on the controller working but the same style of logic does not allow other methods to be public for some reason?
Here is the controller code I am trying to make the add method public on:
<?php
namespace App\Controller\Api;
use App\Controller\Api\AppController;
use Cake\Event\Event;
class UserInfoController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('add');
}
public function add()
{
$this->Crud->on('afterSave', function(\Cake\Event\Event $event) {
if ($event->subject->created) {
$this->set('data', [
'id' => $event->subject->entity->id,
'message' => 'Request Saved!'
]);
$this->Crud->action()->config('serialize.data', 'data');
}
});
return $this->Crud->execute();
}
}
I make the request http://localhost:8765/api/userinfo with POST and the correct JSON only to get a 401 unauthorized exception. My UserController is practially identical to the "Bravo" tutorial and has no problems with the public add() method. Is there something I am doing wrong or are the restrictions set by the plugin too "aggresive" for what I want to accomplish?
UPDATE - For some reason it will only work if I add the following route definition to alias the add method (but again only the alias will work not the direct api/userinfo call):
Router::connect('/api/userinfo/create', ['controller' => 'UserInfo', 'action' => 'add', 'prefix' => 'api']);
There is an error in the documentation which has had me on a wild goose chase ;-)
the config params read
'authenticate', [ ... ]
but should read
'authenticate' => [ ... ]
I have this unit test
public function testEmployeeSignIn() {
$this->configRequest([
'headers' => [
'authorization' => 'Bearer: oauth-token'
]
]);
$this->post('/api/transactions/add', $this->getPostData("IN"));
$this->assertResponseOk();
}
How do I get the token to put it in the header?
there is the functionality of RefreshToken?
Hello, I have been looking all around for a couple hours with no answer. I completed this tutorial:
http://www.bravo-kernel.com/2015/04/how-to-build-a-cakephp-3-rest-api-in-minutes/
It works great locally but the same code on my production server (Siteground) and I keep getting this error:
{
"message": "You are not authorized to access that location.",
"url": "/customers",
"code": 401
}
I did add this to .htaccess:
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.)
RewriteRule . - [e=HTTP_AUTHORIZATION:%1]
I also checked http://jwt.io/ and validated my token, not sure what to do, please point me in the right direction
here is my UsersController:
<?php
namespace App\Controller;
use Cake\Event\Event;
use Cake\Network\Exception\UnauthorizedException;
use Cake\Utility\Security;
use Firebase\JWT\JWT;
class UsersController extends AppController{
public function initialize(){
parent::initialize();
$this->Auth->allow(['add', 'token']);
}
public function add(){
$this->Crud->on('afterSave', function(Event $event) {
if ($event->subject->created) {
$this->set('data', [
'id' => $event->subject->entity->id,
'token' => JWT::encode(
[
'sub' => $event->subject->entity->id,
'exp' => time() + 604800
],
Security::salt())
]);
$this->Crud->action()->config('serialize.data', 'data');
}
});
return $this->Crud->execute();
}
public function token(){
$user = $this->Auth->identify();
if (!$user) {
throw new UnauthorizedException('Invalid username or password');
}
$this->set([
'success' => true,
'data' => [
'token' => JWT::encode([
'sub' => $user['id'],
'exp' => time() + 604800
],
Security::salt())
],
'_serialize' => ['success', 'data']
]);
}
}
I was using like the readme example but was not behaving stateless:
$this->loadComponent('Auth', [
'authenticate', [
'ADmad/JwtAuth.Jwt' => [
'storage' => 'Memory'
'userModel' => 'Users',
'fields' => [
'username' => 'id'
],
'parameter' => 'token',
// Boolean indicating whether the "sub" claim of JWT payload
// should be used to query the Users model and get user info.
// If set to `false` JWT's payload is directly returned.
'queryDatasource' => true,
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize',
]);
So I made a request sending the JWT
and all requests after that even if without JWT
was authorized
and if I did $this->Auth->user()
I was getting the user, again, even if when I was not sending the JWT
.
I just moved the storage
outside authenticate
node and now everything is working properly:
$this->loadComponent('Auth', [
'storage' => 'Memory'
'authenticate', [
'ADmad/JwtAuth.Jwt' => [
'userModel' => 'Users',
'fields' => [
'username' => 'id'
],
'parameter' => 'token',
// Boolean indicating whether the "sub" claim of JWT payload
// should be used to query the Users model and get user info.
// If set to `false` JWT's payload is directly returned.
'queryDatasource' => true,
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize',
]);
Thank you for this, I have a situation where I use a separate table for users and tokens joined by a one-to-many relationship, is there way to make it work without having to add an additional username field at the tokens table? Would it check all the available keys or just the first one it finds?
I found something that might be useful and could save you a few hours of debugging.
The getallheaders() function returns the header fields case-insensitive, so the header "Authorization" may not be found in certain requests.
http://php.net/manual/en/function.getallheaders.php#52029
Sorry, my English is limited, I used Google Translate
I have a login-form where the user can either enter e-mail, nickname or mobile no as username. At the moment it obviously works only with one field. What is the best way to extend that functionality? I tried to extend the class JwtAuthenticate and override _findUser but it didn't work so far.
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'Users',
'fields' => [
'username' => 'email',
'password' => 'password'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
]);
I have issues logging in with a POST request on www.example.com/users/token with an email
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
Putting in 'Form' before 'ADmad/JwtAuth.Jwt' works fine, but causes problems with the tokens.
I wonder if it is more likely for plugin to make the response code 401 when the token expired error rises.
the current response code is 500
I already know it can be done in my project ;)
I've followed this tuto : http://www.bravo-kernel.com/2015/04/how-to-add-jwt-authentication-to-a-cakephp-3-rest-api/
I tried to change the entity "Users" by "Logins". "Users" uses username and password for authentication, and "Logins" uses email and password as fields for authentication.
It's working with Users but not with Logins.
I can't find where's the issue. You can check the work I've done for this issue on this repo : https://github.com/Piclebeuh/cake3api.app
Thanks
is there an alternative to solve this problem?
Hello, great plugin, very useful.
The plugin uses firebase JWT to authenticate based on the given token.
However, if the token is expired, firebase throws an ExpiredException, which results in a generic 500 error code.
This can make things problematic when trying to connect the backend with a client-side frontend, as RESTful apps generally check for a 401 error to know they need a new login. A 500 error can mean anything. Yes, a good client-side program can just know when it needs to throw away the token, but with RESTful APIs it is assumed it will serve a wide variety of client-side apps.
It is possible?? I need use your ::getToken()
.
I need to change UserModel but it's doesn't work... why ?
When adding a different header value than bearer combined with the token an 'UnexpectedValueException' with message 'Wrong number of segments'. This prevents other authentication handlers from using the authorization header for authentication.
How to use with acl
I set up all the acl and authentication but by doing a get it returns me
AclNode :: node () - Could not find Aros node identified by "Array ([Aros0.model] => Users [Aros0.foreign_key] => 1)"
My controller
$this->loadComponent('Auth', [ 'authorize' => [ 'Acl.Actions' => ['actionPath' => 'controllers/'] ], 'authenticate' => [ AuthComponent::ALL => ['userModel' => 'Employes'], 'Form' => [ 'fields' => [ 'username' => 'email', 'password' => 'senha' ], 'scope' => ['Employes.status' => 1] ], 'ADmad/JwtAuth.Jwt' => [ 'parameter' => 'token', 'scope' => ['Employes.status' => 1], 'queryDatasource' => true ] ], 'unauthorizedRedirect' => false, 'checkAuthIn' => 'Controller.initialize', 'storage' => 'Memory' ]);
The name of my tables employes and roles where they are configured
Employes entity
public function parentNode() { if (!$this->id) { return null; } if (isset($this->role_id)) { $roleId = $this->role_id; } else { $employes = TableRegistry::get('Employes'); $employes = $employes->find('all', ['fields' => ['role_id']])->where(['id' => $this->id])->first(); $roleId = $employes->role_id; } if (!$roleId) { return null; } return ['Roles' => ['id' => $roleId]]; }
Since firebase\JWT version 3.0 they added \Firebase\JWT namespace, so the readme part about generating the token should be modified like this
Token Generation
You can use \Firebase\JWT\JWT::encode() [...]
Hello, thank you very much for this plugin, my question is: how can I expire the token at the time of making a logout in the application ?, try with the typical $ this->Auth->logout(), but the session and the token is not destroy.
kinds regards
Hi,
great job!
It would be nice to have a full example of how to implement RESTful api for integrating JWT auth with client side apps
I haven't been able to catch you on IRC so I thought I would raise an issue, I'm not entirely sure where the problem is but since upgrading to the latest version of this plugin, setting an environment variable for authorisation for tests doesn't seem to be working:
I created this function to test it in one place and am running it through xdebug to inspect the data:
So at this point the plugin has returned the token and I have written it to the environment:
Before I step into PHPUnit's GET function - you can see that I am Authorised in $_SESSION['Auth']
I step into PHPUnit's GET function and can see the Environment variable is still set there so all seems good so far (I am also still Authorized in SESSION['Auth'])
But on the other side of it - Auth is now telling me I am not authorized and I really dont understand why? (The environment variable is still there at this point as well).
The line it occurs on is 109 of Dispatcher.php: $result = $controller->startupProcess();
Before this line my user is in Auth and as soon as the startupProcess is called on the comments controller it removes the Auth and replaces it with a redirect and a Flash message saying not Authorised
My AppController initialize is:
public function initialize()
{
parent::initialize();
$this->loadComponent('Flash');
$this->loadComponent('RequestHandler');
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
'Crud.View'
]
]);
$this->Crud->addListener('relatedModels', 'Crud.RelatedModels');
$this->Crud->addListener('Crud.Api');
$this->Crud->addListener('Crud.ApiQueryLog');
//JWT Auth
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
],
'unauthorizedRedirect' => false,
'authenticate' => [
'ADmad/JwtAuth.Jwt' => [
'storage' => (Configure::read('debug') ? "Session" : "Memory"),
'parameter' => 'token',
'queryDatasource' => true,
'userModel' => 'Users',
'scope' => ['Users.active' => 1],
'fields' => [
'id' => 'id'
]
],
'Form' => [
'passwordHasher' => [
'className' => 'Legacy'
]
]
]
]);
}
Am I doing something idiotic or is there some gotcha I need to be aware of in the new version? I saw your notes on ensuring the server set either $_SERVER or $_ENV - I have tried both to no avail.
I'll also add that for development purposes I am using Auth->setUser as well so I can run requests on the front end without having to use postman for all get requests
hi @ADmad thanks for the beautiful plugin you made for the cakephp community, I am very confused about, that how can I get the logged in user id in other api's after logged in and sending the token received in login api?
please reply as fast as possible i will be very thankful of yours
Hi @ADmad
I was working in my local PC testing my app with bin\cake server
and every thing was OK.
but when I upload my app to the server I had an issue that my request header Authorization is always null.
I made two reuest in the same time one to the test server and one to the remote server and made some checks.
I found that the problem starts from environment because this array is different in the two servers.
this is the test server _environment array
[
{
"DOCUMENT_ROOT": "...",
"REMOTE_ADDR": "::1",
"REMOTE_PORT": "50858",
"SERVER_SOFTWARE": "PHP 5.5.12 Development Server",
"SERVER_PROTOCOL": "HTTP/1.1",
"SERVER_NAME": "localhost",
"SERVER_PORT": "8765",
"REQUEST_URI": "/api/users/token",
"REQUEST_METHOD": "GET",
"SCRIPT_NAME": "/index.php",
"SCRIPT_FILENAME": "D:\\...",
"PATH_INFO": "/api/users/token",
"PHP_SELF": "/index.php",
"HTTP_HOST": "localhost:8765",
"HTTP_CONNECTION": "keep-alive",
"HTTP_AUTHORIZATION": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJlNjY2ZTE5Ny03NGQzLTRkNmMtOWFlMS0yYmU5ZWFiNzYzNDkiLCJleHAiOjE0NjU5Nzc1OTV9.H6ZxKsmEdc5huQ5lXYLf2Mz-4Thb1sQs1BLbJIGwjdc",
"HTTP_CACHE_CONTROL": "no-cache",
"HTTP_USER_AGENT": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"HTTP_POSTMAN_TOKEN": "88e43421-63a1-9530-1f2c-2d7f4c3c6ad7",
"HTTP_ACCEPT": "*/*",
"HTTP_ACCEPT_ENCODING": "gzip, deflate, sdch",
"HTTP_ACCEPT_LANGUAGE": "tr-TR,tr;q=0.8,en-US;q=0.6,en;q=0.4",
"REQUEST_TIME_FLOAT": 1465373939.0754,
"REQUEST_TIME": 1465373939,
"HTTP_X_HTTP_METHOD_OVERRIDE": null,
"ORIGINAL_REQUEST_METHOD": "GET",
"HTTPS": false,
"HTTP_X_REQUESTED_WITH": null
}
]
this is the remote server _environment array
[
{
"REDIRECT_REDIRECT_STATUS": "200",
"REDIRECT_STATUS": "200",
"HTTP_HOST": "server.com",
"HTTP_CONNECTION": "keep-alive",
"HTTP_CACHE_CONTROL": "no-cache",
"HTTP_USER_AGENT": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"HTTP_POSTMAN_TOKEN": "3e6afeb1-410c-5e95-2dcd-11c72df55941",
"HTTP_ACCEPT": "*/*",
"HTTP_ACCEPT_ENCODING": "gzip, deflate, sdch",
"HTTP_ACCEPT_LANGUAGE": "tr-TR,tr;q=0.8,en-US;q=0.6,en;q=0.4",
"HTTP_COOKIE": "CAKEPHP=r7gi0qkpcgfbg9au1h9bc3bvf3",
"PATH": "C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\wamp\\bin\\php\\php5.5.12;C:\\Program Files (x86)\\Git\\cmd;C:\\ProgramData\\ComposerSetup\\bin;C:\\Program Files\\nodejs\\;C:\\Program Files (x86)\\Windows Kits\\8.1\\Windows Performance Toolkit\\;C:\\Program Files\\Microsoft SQL Server\\110\\Tools\\Binn\\;C:\\Program Files (x86)\\Microsoft SDKs\\TypeScript\\1.0\\;C:\\Program Files\\Microsoft SQL Server\\120\\Tools\\Binn\\",
"SystemRoot": "C:\\Windows",
"COMSPEC": "C:\\Windows\\system32\\cmd.exe",
"PATHEXT": ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC",
"WINDIR": "C:\\Windows",
"SERVER_SIGNATURE": "<address>Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12 Server at server.com Port 80</address>\n",
"SERVER_SOFTWARE": "Apache/2.4.9 (Win64) OpenSSL/1.0.1g PHP/5.5.12",
"SERVER_NAME": "server.com",
"SERVER_ADDR": "192.168.85.21",
"SERVER_PORT": "80",
"REMOTE_ADDR": "76.44.73.54",
"DOCUMENT_ROOT": "C:/wamp/www/",
"REQUEST_SCHEME": "http",
"CONTEXT_PREFIX": "",
"CONTEXT_DOCUMENT_ROOT": "C:/wamp/www/",
"SERVER_ADMIN": "[email protected]",
"SCRIPT_FILENAME": "C:/wamp/www/reporter/webroot/index.php",
"REMOTE_PORT": "50837",
"REDIRECT_URL": "/reporter/webroot/api/users/token",
"GATEWAY_INTERFACE": "CGI/1.1",
"SERVER_PROTOCOL": "HTTP/1.1",
"REQUEST_METHOD": "GET",
"QUERY_STRING": "",
"REQUEST_URI": "/reporter/api/users/token",
"SCRIPT_NAME": "/reporter/webroot/index.php",
"PHP_SELF": "/reporter/webroot/index.php",
"REQUEST_TIME_FLOAT": 1465373833.462,
"REQUEST_TIME": 1465373833,
"HTTP_X_HTTP_METHOD_OVERRIDE": null,
"ORIGINAL_REQUEST_METHOD": "GET",
"HTTPS": false,
"HTTP_X_REQUESTED_WITH": null
}
]
I will make a patch to explain how I fixed the issue as an instant solution
If I don't force plugin config with :
'unauthenticatedException' => 'Cake\Http\Exception\UnauthorizedException'
I always have the depracation warning.
After investigate, if I switch in JwtAuthenticate (l.101 ) from :
if (!class_exists(UnauthorizedException::class, false)) {
to :
if (!class_exists(UnauthorizedException::class)) {
So everything's fine ... is there anything to do, or have I to force the UnauthorizedException class on plugin config ?
If I omit the exp
in the creating of the token, the token will live forever or theres some default value of expiration when we omit it?
How to implement a login for both username OR email , is it possible ?
Hey,
Do you have any plans to store the tokens somewhere to work with refresh-tokens?
The plugin looks good and trying it :)
Some extra docs would be welcome (as said earlier). Maybe I got some time once....
Greetz
Bob
How do I put expiration time on the token, do I do this on the frontend or the backend?
I am getting this error when Authorization
header is not present or empty:
Notice Error: Undefined variable: token in [vendor/admad/cakephp-jwt-auth/src/Auth/JwtAuthenticate.php, line 197]
Hi
I am trying to run test case for the plugin and I added
<testsuites>
<testsuite name="App Test Suite">
<directory>./tests/TestCase</directory>
</testsuite>
<!-- Add plugin test suites here. -->
<testsuite name="JWT AUTH plugin">
<directory>./vendor/admad/cakephp-jwt-auth/tests/TestCase</directory>
</testsuite>
</testsuites>
to phpunit.xml.dist file . When I run vendor/bin/phpunit from command line I am getting an Exception
Exception: Referenced fixture class "ADmad\JwtAuth\Test\Fixture\UsersFixture" not found. Fixture "plugin.ADmad\JwtAuth.users" was referenced in test case "ADmad\JwtAuth\Auth\Test\TestCase\Auth\JwtAuthenticateTest". in [/var/www/html/swiftmail/app/vendor/cakephp/cakephp/src/TestSuite/Fixture/FixtureManager.php, line 180]
Can you please help here with this ?
Hi,
not sure if it's a bug or I'm doing something wrong but when I use JWT auth, everything works correctly but afterwards $this->Auth->user() returns null.
thanks, dan
Hi i follow all the istruction login via username work but if i want to login with email?
Hello,
I tried to use this plugin as described [here ](http://www.bravo-kernel.com/2015/04/how-to-add-jwt-authentication-to-a-cakephp-3-rest-api/ but for some reason it does not work as described - at least for me.
Authentication works fine. I get the token but when I try to pass the token to the API for requesting resources I get a "404" not found meesage. I cannot determine a 100% if this is an issue concerning this plugin but when I disable the authentication, I can request the resources as I could before the authentication.
AppController looks pretty straight forward:
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'Form' => ['userModel' => 'Users'],
'ADmad/JwtAuth.Jwt' => [
'parameter' => '_token',
'userModel' => 'Users',
'fields' => [
'username' => 'username',
'password' => 'password'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
]);
}
EDIT: I think it makes sense also to post the routes.php:
Router::scope('/', function (RouteBuilder $routes) {
$routes->connect(
'/:path',
['controller' => 'Pages', 'action' => 'display', 'home'],
['path' => '.*']
);
$routes->scope('/api/', function($routes) {
$list = ['map' => ['list' => [
'action' => 'list',
'method' => 'POST',
'path' => '/list'
]]];
$routes->resources('Users', $list);
$routes->resources('Users', ['map' => ['login' => [
'action' => 'login',
'method' => 'POST',
'path' => '/login'
]]]);
});
The token generating method in UsersController:
public function login()
{
$user = $this->Auth->identify();
if (!$user) {
$this->viewBuilder()->className('Json');
$this->set([
'success' => false,
'data' => null,
'_serialize' => ['success', 'data']
]);
} else {
$this->viewBuilder()->className('Json');
$this->set([
'success' => true,
'data' => [
'token' => JWT::encode([
'sub' => [
'username' => $user['username'],
],
'exp' => time() + 604800
],
Security::salt())
],
'_serialize' => ['success', 'data']
]);
}
}
This is how a dummy request looks like:
Host: localhost:4100
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.7,de;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost:4100/admin
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOnsidXNlcm5hbWUiOiJ0ZXN0In0sImV4cCI6MTUxMjg0MDUzNn0.ckqcOEUELdoUoUgFF1n5zcLVTKjig9cYKWO2l6F43jM
Content-Type: application/json
Content-Length: 224
DNT: 1
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
I tried to pass it through _token parameter:
{"_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOnsidXNlcm5hbWUiOiJ0ZXN0In0sImV4cCI6MTUxMjg0MDUzNn0.ckqcOEUELdoUoUgFF1n5zcLVTKjig9cYKWO2l6F43jM","filter":"","page":1,"pageSize":25,"sort":{"active":"","direction":""}}
All of the above configuration didn't work. Furthermore, I realized that passing the token to debugger on jwt.io results to an invalid signature. As mentioned before I get a "404 Missing Routes Error". What am I doing wrong?
EDIT: I use "cakephp/cakephp": "3.5.*"
i want validate existing token when access API or controller methods
Just curious. Would it be difficult to backport this plugin to CakePHP 2.x? Or is it an effort not worth undertaking?
Thank you
pls
Thank you so much for implementing this, it is extremely helpful in my development. I have a question, if I wanted to use 'email' rather than 'username' to check the db, how would I modify the app? I'm using an already existing database that uses 'email' instead of 'username' for the users credentials? Also, the database uses 'pin' instead of 'password', how could I modify the structure to accommodate for the changes in database structure? Thanks again!
Hi,
I'm always getting error "Signature verification failed" and I'm not sure why it's happening, because apparently everything is fine (in my cakephp project at least). Btw, the website is accessed using the https protocol ( not sure if it matters ). PHP version 7; Cakephp 3.6 & Apache 2 server.
{
"message": "Signature verification failed",
"url": "\/api\/users.json",
"code": 500,
"file": "\/var\/www\/Development\/appname\/vendor\/firebase\/php-jwt\/src\/JWT.php",
"line": 112
}
To get to this point before I had to disable apache authentication with AuthType None because apache itself returned a 501 error. I also tried to get it working messing with the .htaccess but everything i tried didn't worked.
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
When I got the answer from cakephp instead of apache I started to track the matter and tried to put the jwt token into a validator ( https://jwt.io/ ) with the cake salt and and it seems to be valid (Signature verified).
All the base files of the library have not been modified. Here's my code:
AppController.php
namespace App\Controller\Api;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller {
use \Crud\Controller\ControllerTrait;
public function initialize() {
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
'Crud.View',
'Crud.Add',
'Crud.Edit',
'Crud.Delete'
],
'listeners' => [
'Crud.Api',
'Crud.ApiPagination',
'Crud.ApiQueryLog'
]
]);
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'Form' => [
'fields' => ['username' => 'username', 'password' => 'password'],
'scope' => ['Users.active' => 1]
],
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'Users',
'scope' => ['Users.active' => 1],
'fields' => [
'username' => 'id'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize',
'loginAction' => true
]);
}
}
UsersController.php ( where token is created )
public function index()
{
$this->loadmodel('Users');
$this->paginate = [
'order' => ['username' => 'ASC']
];
$users = $this->paginate($this->Users);
$this->set([
'users' => $users,
'_serialize' => ['users']
]);
}
public function token() {
$user = $this->Auth->identify();
if (!$user) {
throw new UnauthorizedException('Invalid username or password');
} else {
$this->set([
'success' => true,
'data' => [
'token' => JWT::encode([
'sub' => $user['id'],
'exp' => time() + 604800
],
Security::salt())
],
'_serialize' => ['success', 'data']
]);
}
}
I'm missing something?
Sorry for the Translator English :_(
Thanks.
I'm using CakePHP 3.6
and this plugin to add REST to my application.
All works fine in localhost but after moving to the server, it gives 401 error
{
"success": false,
"data": {
"message": "You are not authorized to access that location.",
"url": "/api/client_accounts",
"code": 401
}
}
I have posted a question with more detail on Stackoverflow.
https://stackoverflow.com/q/52286806/3719167
I have also added the following in .htaccess
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^(\.well-known/.*)$ $1 [L]
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
</IfModule>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.