{"id":13684102,"url":"https://github.com/rrd108/api-token-authenticator","last_synced_at":"2025-08-10T20:06:50.049Z","repository":{"id":44412374,"uuid":"384445889","full_name":"rrd108/api-token-authenticator","owner":"rrd108","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-04T16:32:31.000Z","size":1161,"stargazers_count":3,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-28T15:09:05.699Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rrd108.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-07-09T13:30:11.000Z","updated_at":"2023-11-03T16:59:45.000Z","dependencies_parsed_at":"2022-09-16T02:03:43.312Z","dependency_job_id":"1a8a9a6f-15ba-4670-85c7-6deccadd465f","html_url":"https://github.com/rrd108/api-token-authenticator","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/rrd108/api-token-authenticator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrd108%2Fapi-token-authenticator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrd108%2Fapi-token-authenticator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrd108%2Fapi-token-authenticator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrd108%2Fapi-token-authenticator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rrd108","download_url":"https://codeload.github.com/rrd108/api-token-authenticator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrd108%2Fapi-token-authenticator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269780617,"owners_count":24474686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T14:00:25.968Z","updated_at":"2025-08-10T20:06:50.020Z","avatar_url":"https://github.com/rrd108.png","language":"PHP","funding_links":[],"categories":["Authentication and Authorization","Plugins"],"sub_categories":["Authentication and Authorization"],"readme":"# CakePHP ApiTokenAuthenticator Plugin\n\nA Simple Token Authentication Plugin for CakePHP 5 REST API-s.\n\nFor CakePHP 4 version see [rrd108/api-token-authenticator](https://github.com/rrd108/api-token-authenticator/tree/cakephp-4)\n\nFor a REST API you may want to use a cors plugin like [rrd108/cakephp-cors](https://github.com/rrd108/cakephp-cors) and a json api exception plugin like [rrd108/cakephp-json-api-exception](https://github.com/rrd108/cakephp-json-api-exception).\n\nIf you use vuejs as your frontend you may wnat to bake your vue components with [rrd108/vue-bake](https://github.com/rrd108/vue-bake).\n\n## Configuration\n\n### `Users` table\n\nIn your `users` table you should have a field named `token`, or whatever name you choose for the token. We will use `token` in the examples. The `token` value will not be automatically generated by the plugin. You can generate it in your `UsersController.php` file's `login()` method (or elsewhere if you want). See the example below.\n\n### Changing the default settings\n\nIf you are happy with the default settings, you can skip this section.\n\nFor defaults see `config/apiTokenAuthenticator.php` file in the plugin's directory.\n\nIf you want to change any of the values then create your own `config/apiTokenAuthenticator.php` file at your project's `config` directory. In your config file, you should use _only_ those keys that you want to change. It will be merged to the default one. So, for example, if you are happy with all the options, except in your case the token's header name is `Authorization`, then you have to put this into your on config file.\n\n```php\n\u003c?php\nreturn [\n  'ApiTokenAuthenticator' =\u003e [\n    'header' =\u003e 'Authorization',\n  ]\n];\n```\n\n#### Authorization with Bearer token\n\nIf you want to use the `Authorization` header with `Bearer` token, you should set the `header` key to `Authorization` and the `prefix` key to `Bearer` in your `config/apiTokenAuthenticator.php` file.\n\n```php\n\u003c?php\nreturn [\n  'ApiTokenAuthenticator' =\u003e [\n    'header' =\u003e 'Authorization',\n    'prefix' =\u003e 'Bearer',\n  ]\n];\n```\n\n## Authentication\n\nThe plugin authentication workflow is the following.\n\nAt your client appliacation you should send a POST request to `/users/login.json` (or what you set in your `config/apiTokenAuthenticator.php` file) with a JSON object like this.\n\n```json\n{\n    \"email\": \"rrd@webmania.cc\",\n    \"password\": \"rrd\"\n}\n```\n\nIf the login was successful than you will get a response like this.\n\n```json\n{\n    \"user\": {\n        \"id\": 1,\n        \"token\": \"yourSecretTokenComingFromTheDatabase\"\n    }\n}\n```\n\nThan you can use this `token` to authenticate yourself for accessing urls what requires authentication. The `token` should be sent in a request header named `Token` (or what you set in your `config/apiTokenAuthenticator.php` file).\n\n## Installation\n\n### 1. Install the plugin\n\nIncluding the plugin is pretty much as with every other CakePHP plugin:\n\n```bash\ncomposer require rrd108/api-token-authenticator\n```\n\nThen, to load the plugin either run the following command:\n\n```bash\nbin/cake plugin load ApiTokenAuthenticator\n```\n\nor manually add the following line to your app's `config/plugins.php`:\n\n```php\nreturn [\n  // other plugins\n  'ApiTokenAuthenticator' =\u003e [],\n];\n```\n\n### 2. Disable CSRF protection\n\nYou should comment out (or delete) `CsrfProtectionMiddleware` in your `/src/Application.php` file's `middleware()` method.\n\n### 3. Load the plugin's components\n\nAt your `AppController.php` file's `initialize()` function you should include these components:\n\n```php\npublic function initialize(): void\n{\n  parent::initialize();\n  $this-\u003eloadComponent('Authentication.Authentication');\n}\n```\n\nAnd add JSON view support to `AppController.php`.\n\n```php\nuse Cake\\View\\JsonView;\n\npublic function viewClasses(): array\n{\n  return [JsonView::class];\n}\n```\n\n### 4. Set password hasher\n\nUpdate your `src/Model/Entity/User.php` file adding the following.\n\n```php\nuse Authentication\\PasswordHasher\\DefaultPasswordHasher;\nprotected function _setPassword(string $password)\n{\n  $hasher = new DefaultPasswordHasher();\n  return $hasher-\u003ehash($password);\n}\n```\n\nDo not forget to remove the `token` field from the `$_hidden` array.\n\n### 5. Set extensions for `routes`\n\nAs you probably will use JSON urls, do not forget to add this line to your `config/routes.php` file.\n\n```php\n$routes-\u003escope('/', function (RouteBuilder $builder): void {\n  // other routes\n  $builder-\u003esetExtensions(['json']);\n  $builder-\u003eresources('Users');\n\n  $builder-\u003efallbacks();\n});\n```\n\n### 5. Set JSON response in controllers\n\nIn your controllers you should set the JSON response type.\n\n```php\n// for example in UsersController.php\npublic function index()\n{\n  $query = $this-\u003eUsers-\u003efind();\n  $users = $this-\u003epaginate($query);\n\n  $this-\u003eset(compact('users'));\n  $this-\u003eviewBuilder()-\u003esetOption('serialize', ['users']);\n}\n```\n\nAs CakePHP response use content type negotiation it is important to add the `Accept: application/json` header to your requests.\n\nThat's it. It should be up and running.\n\n## The `login()` method\n\n### If you use static `tokens`\n\nLogin method is not added automatically, you should implement it. Here is an example how.\n\n```php\npublic function login()\n{\n  $result = $this-\u003eAuthentication-\u003egetResult();\n  if ($result-\u003eisValid()) {\n    $user = $this-\u003eAuthentication-\u003egetIdentity()-\u003egetOriginalData();\n    $this-\u003eset(compact('user'));\n    $this-\u003eviewBuilder()-\u003esetOption('serialize', ['user']);\n  }\n}\n```\n\nThe `login` method should be added to the list of actions that are allowed to be accessed without authentication.\n\n```php\npublic function beforeFilter(\\Cake\\Event\\EventInterface $event)\n{\n  parent::beforeFilter($event);\n  $this-\u003eAuthentication-\u003eallowUnauthenticated(['login']);\n}\n```\n\n### If you use dynamic `tokens`\n\n```php\npublic function login()\n{\n  $result = $this-\u003eAuthentication-\u003egetResult();\n  if ($result-\u003eisValid()) {\n    $user = $this-\u003eAuthentication-\u003egetIdentity()-\u003egetOriginalData();\n    $user-\u003etoken = $this-\u003egenerateToken();\n    $user = $this-\u003eUsers-\u003esave($user);\n    $user = $this-\u003eUsers-\u003eget($user-\u003eid);\n\n    $this-\u003eset(compact('user'));\n    $this-\u003eviewBuilder()-\u003esetOption('serialize', ['user']);\n  }\n  // if login failed you can throw an exception, suggested: rrd108/cakephp-json-api-exception\n}\n\nprivate function generateToken(int $length = 36)\n{\n  $random = base64_encode(Security::randomBytes($length));\n  $cleaned = preg_replace('/[^A-Za-z0-9]/', '', $random);\n  return substr($cleaned, 0, $length);\n}\n```\n\n## Token expiration\n\nBy default tokens are not invalidated by the plugin, you can use them permanently or as long as there is no new login session like in the example code above.\n\nIf you want the plugin to use tokens only for a certain period of time, you should do the following steps.\n\n1. Add a column to your `users` table named `token_expiration` and set it's type to `datetime`. You can use a different field name, but you have to change it in the following steps.\n\n2. In your `config/apiTokenAuthenticator.php` file set `'tokenExpiration' =\u003e 'token_expiration'`.\n\n3. Update your `src/Model/Entity/User.php` file adding the field to the `$accessible` array.\n\n```php\nprotected $_accessible = [\n  'email' =\u003e true,\n  // your other fields here\n  'token' =\u003e true,\n  'token_expiration' =\u003e true,\n];\n```\n\n4. Update your `src/Model/Table/UsersTable.php` file adding the following.\n\n```php\n$validator\n  -\u003edateTime('token_expiration')\n  -\u003eallowEmptyDateTime('token_expiration');\n```\n\n5. In your `src/Controller/UsersController.php` file you should modify `login()` method.\n\n```php\npublic function login()\n{\n  $result = $this-\u003eAuthentication-\u003egetResult();\n  if ($result-\u003eisValid()) {\n    $user = $this-\u003eAuthentication-\u003egetIdentity()-\u003egetOriginalData();\n    list($user-\u003etoken, $user-\u003etoken_expiration) = $this-\u003egenerateToken();\n    $user = $this-\u003eUsers-\u003esave($user);\n\n    $this-\u003eset(compact('user'));\n    $this-\u003eviewBuilder()-\u003esetOption('serialize', ['user']);\n\n    // delete all expired tokens\n    $this-\u003eUsers-\u003eupdateAll(\n      ['token' =\u003e null, 'token_expiration' =\u003e null],\n      ['token_expiration \u003c' =\u003e Chronos::now()]\n    );\n  }\n}\n\nprivate function generateToken(int $length = 36, string $expiration = '+6 hours')\n{\n  $random = base64_encode(Security::randomBytes($length));\n  $cleaned = preg_replace('/[^A-Za-z0-9]/', '', $random);\n  return [$cleaned, strtotime($expiration)];\n}\n```\n\n## Access without authentication\n\nIf you want to let the users to access a resource without authentication you should state it in the controller's `beforeFilter()` method. The `login`, `register` methods are good candidates to allow unauthenticated access.\n\n```php\n// in UsersController.php\npublic function beforeFilter(\\Cake\\Event\\EventInterface $event)\n{\n  parent::beforeFilter($event);\n  $this-\u003eAuthentication-\u003eallowUnauthenticated(['login', 'index']);\n}\n```\n\nThis will allow users to access `/users/login.json` and `/users.json` url without authentication.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frrd108%2Fapi-token-authenticator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frrd108%2Fapi-token-authenticator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frrd108%2Fapi-token-authenticator/lists"}