Skip to content

Commit ef3c8cb

Browse files
authored
Merge pull request #149 from dotkernel/v7-overhaul
V7 overhaul
2 parents 4bc50b1 + a5dcdd7 commit ef3c8cb

12 files changed

Lines changed: 955 additions & 191 deletions

docs/book/v7/core-features/authentication.md

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@ It ensures that the entity making the request has the proper credentials to acce
66
**Dotkernel API** identities are delivered to the application from the client through the `Authorization` request.
77
If it is present, the application tries to find and assign the identity to the application.
88
If it is not presented, Dotkernel API assigns a default `guest` identity, represented by an instance of the class `Mezzio\Authentication\UserInterface`.
9+
Guests can access public endpoints but cannot access protected resources (those requiring user or admin roles).
10+
Check out the [Authorization page](https://docs.dotkernel.org/api-documentation/v7/core-features/authentication/) for more details on role-based access.
911

1012
## Configuration
1113

14+
Dotkernel API uses the **OAuth2 password grant flow** for authentication.
15+
This allows users to exchange their credentials (username/password) for access tokens.
16+
These tokens are then used for later requests instead of repeatedly sending credentials.
17+
1218
Authentication in Dotkernel API is built around the `mezzio/mezzio-authentication-oauth2` component and is already configured out of the box.
13-
But if you want to dig more, the configuration is stored in `config/autoload/local.php` under the `authentication` key.
19+
To customize authentication behavior (token lifetimes, algorithms, etc.), edit `config/autoload/local.php` under the `authentication` key.
20+
See the [Mezzio OAuth2 documentation](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration) for all available options.
1421

1522
> You can check the
1623
> [mezzio/mezzio-authentication-oauth2](https://docs.mezzio.dev/mezzio-authentication-oauth2/v1/intro/#configuration)
@@ -23,32 +30,46 @@ It allows each user of your application to generate API tokens for their account
2330

2431
The authentication happens through the middleware in the `Api\App\Middleware\AuthenticationMiddleware`.
2532

26-
## Database
33+
### Database
2734

28-
When you install **Dotkernel API** for the first time, you need to run the migrations and seeders.
35+
When you install **Dotkernel API** for the first time, you need to run the migrations and seeders (fixtures).
2936
All the tables required for authentication are automatically created and populated.
3037

31-
In Dotkernel API, authenticated users come from either the `admin` or the `user` table.
32-
We choose to keep the admin table separated from the users to prevent users of the application from accessing sensitive data, which only the administrators of the application should access.
38+
```shell
39+
php ./vendor/bin/doctrine-migrations migrate
40+
php ./bin/doctrine fixtures:execute
41+
```
42+
43+
The commands above create OAuth tables (oauth_clients, oauth_scopes, oauth_*) and seed the initial credentials:
44+
45+
- **Admin**: identity=admin, password=dotadmin
46+
- **User**: identity=test@dotkernel.com, password=dotkernel
3347

34-
The `oauth_clients` table is pre-populated with the default `admin` and `frontend` clients with the same password as their names (**we recommend you change the default passwords**).
48+
Check out the [Installation Guide](https://docs.dotkernel.org/api-documentation/v7/installation/doctrine-orm/) for more details.
3549

36-
As you guessed each client serves to authenticate `admin` or `user`.
50+
In Dotkernel API, authenticated users come from either the `admin` or the `user` tables.
51+
We chose to keep the admin and user tables separate to prevent users of the application from accessing sensitive data that only administrators should access.
3752

3853
Another table that is pre-populated is the `oauth_scopes` table, with the `api` scope.
3954

4055
### Issuing API Tokens
4156

4257
Token generation in Dotkernel API is done using the `password` `grant_type` scenario, which in this case allows authentication to an API using the user's credentials (generally a username and password).
4358

44-
The client sends a POST request to the `/security/generate-token` with the following parameters:
59+
The `POST /security/generate-token` endpoint accepts OAuth2 credentials and returns both an access token (for making API calls) and a refresh token (for refreshing expired access tokens).
60+
61+
The client requires the following parameters:
4562

46-
- `grant_type` = password.
47-
- `client_id` = column `name` from the `oauth_clients` table
48-
- `client_secret` = column `secret` from the `oauth_clients` table
49-
- `scope` = column `scope` from the `oauth_scopes` table
50-
- `username` = column `identity` from table `admin`/`user`
51-
- `password` = column `password` from table `admin`/`user`
63+
| Field | Type | Purpose | Example |
64+
|-----------------|--------|----------------------------------------------------------|------------------------|
65+
| `grant_type` | string | OAuth2 flow type | `"password"` |
66+
| `client_id` | string | OAuth client identifier from the `oauth_clients` table | `"frontend"` |
67+
| `client_secret` | string | OAuth client credential from the `oauth_clients` table | `"frontend"` |
68+
| `scope` | string | Permission scope from the `oauth_scopes` table | `"api"` |
69+
| `username` | string | User identity (email/username) from table `admin`/`user` | `"test@dotkernel.com"` |
70+
| `password` | string | User password | `"dotkernel"` |
71+
72+
This is what the call should look like:
5273

5374
```shell
5475
POST /security/generate-token HTTP/1.1
@@ -75,7 +96,14 @@ The server responds with a JSON as follows:
7596
}
7697
```
7798

78-
Next time when you make a request to the server to an authenticated endpoint, the client should use the `Authorization` header request.
99+
| Field | Type | Lifetime | Purpose |
100+
|-----------------|---------|--------------------------------------|---------------------------------------|
101+
| `token_type` | string | N/A | Header value type |
102+
| `expires_in` | integer | N/A | Seconds until access token expires |
103+
| `access_token` | string | 86400 seconds = 1 day (configurable) | Used in `Authorization` header |
104+
| `refresh_token` | string | 1 month (configurable) | Used to refresh expired access tokens |
105+
106+
On later requests to the server for an authenticated endpoint, the client should use the `Authorization` header request.
79107

80108
```shell
81109
GET /users/1 HTTP/1.1
@@ -85,24 +113,22 @@ Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...
85113

86114
### Refreshing tokens
87115

88-
Dotkernel API can refresh the access token, based on the expired access token's `refresh_token`.
89-
90-
The clients need to send a `POST` request to the `/security/refresh-token` with the following request:
116+
When an access token expires, use the refresh token (received during token generation) to obtain a new access token without re-entering credentials:
91117

92118
```shell
93-
POST /security/refresh-token HTTP/1.1
119+
POST /security/refresh-token
94120
Accept: application/json
95121
Content-Type: application/json
96122
{
97123
"grant_type": "refresh_token",
98124
"client_id": "frontend",
99125
"client_secret": "frontend",
100126
"scope": "api",
101-
"refresh_token" : "def5020087199939a49d0f2f818..."
127+
"refresh_token": "def5020087199939a49d0f2f818..."
102128
}
103129
```
104130

105-
The server responds with a JSON as follows:
131+
The response contains a new `access_token` and `refresh_token`:
106132

107133
```json
108134
{
@@ -112,3 +138,50 @@ The server responds with a JSON as follows:
112138
"refresh_token": "def5020087199939a49d0f2f818..."
113139
}
114140
```
141+
142+
## Common Issues
143+
144+
### "Invalid credentials" error
145+
146+
- Check username/password are correct.
147+
- Verify client_id and client_secret match OAuth client in the database.
148+
- Confirm the user account exists and is active.
149+
150+
### "Token has expired" error
151+
152+
- Use refresh_token to get a new access_token.
153+
- If refresh_token is expired, re-authenticate with credentials.
154+
155+
### "Invalid scope" error
156+
157+
- Verify `scope` field is set to `"api"` (the only configured scope)
158+
159+
## Flow Diagram
160+
161+
```quote
162+
User Credentials
163+
164+
POST /security/generate-token
165+
166+
Access Token + Refresh Token
167+
168+
Store tokens securely ←─────────────────────────┐
169+
↓ |
170+
Include Access Token in Authorization header |
171+
↓ |
172+
Make API requests |
173+
↓ |
174+
Token expires? |
175+
↓ (yes) |
176+
POST /security/refresh-token with refresh_token |
177+
↓ |
178+
Get new Access Token ───────────────────────────┘
179+
```
180+
181+
## Security Best Practices
182+
183+
- **Store tokens securely**: Never commit tokens to version control. Use environment variables or secure storage.
184+
- **Use HTTPS only**: OAuth2 tokens should only be transmitted over HTTPS in production.
185+
- **Rotate credentials**: Change default OAuth client secrets in production.
186+
- **Token expiration**: Access tokens expire (default 1 day). Implement refresh logic in clients.
187+
- **Never expose refresh tokens**: Refresh tokens should only be stored client-side, never in logs or public code.
Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,56 @@
11
# Composer Installation of Packages
22

3-
Composer is required to install Dotkernel `api`. You can install Composer from the [official site](https://getcomposer.org/).
3+
In this step you will:
44

5-
> First, make sure that you have navigated your command prompt to the folder where you copied the files in the previous step.
5+
- [Install dependencies](#install-dependencies-using-composer).
6+
- [Enable development mode](#development-mode).
67

7-
## Install dependencies
8+
> Composer is required to install Dotkernel `api`.
9+
> You can install Composer from the [official site](https://getcomposer.org/).
10+
11+
> Before you begin, make sure that you have navigated your command prompt to the folder where you copied the files in the previous step.
12+
13+
## Install Dependencies Using Composer
814

915
Run this command in the command prompt.
1016

1117
> Use the **CLI** to ensure interactivity for proper configuration.
18+
> In some IDEs, Composer may not be able to prompt for configuration settings.
1219
1320
```shell
1421
composer install
1522
```
1623

24+
The automatic setup script performs these tasks:
25+
26+
- Installs the packages listed in the `composer.json` file and their dependencies into the `vendor` folder.
27+
- Creates the `composer.lock` file that locks all dependencies to exact versions (you can still run `composer update` to replace them with newer versions, if available and installable without conflicts).
28+
- Configures PHP CodeSniffer, a utility to detect code style errors in PHP code.
29+
- Generate and save the OAuth2 keys in the `data/oauth` folder.
30+
- Performed by this script `./bin/generate-oauth2-keys.php`.
31+
- Creates the initial `config/autoload` configuration files.
32+
- Performed by this script `./bin/composer-post-install-script.php`.
33+
- These files are created:
34+
- config/autoload/local.php
35+
- config/autoload/local.test.php
36+
- config/autoload/mail.global.php
37+
38+
> The post install commands are run automatically on every `composer install` and `composer update`.
39+
> The scripts check if the files exist to prevent overwriting them.
40+
1741
You should see this text below, along with a long list of packages to be installed instead of the `[...]`.
18-
In this example there are 164 packages, though the number can change in future updates.
19-
You will find the packages in the `vendor` folder.
42+
43+
> In this example there are 146 packages, though the number can change in future updates.
2044
2145
```shell
2246
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
2347
Loading composer repositories with package information
2448
Updating dependencies
25-
Lock file operations: 164 installs, 0 updates, 0 removals
49+
Lock file operations: 146 installs, 0 updates, 0 removals
2650
[...]
2751
Writing lock file
2852
Installing dependencies from lock file (including require-dev)
29-
Package operations: 164 installs, 0 updates, 0 removals
53+
Package operations: 146 installs, 0 updates, 0 removals
3054
[...]
3155
```
3256

@@ -42,8 +66,8 @@ Please select which config file you wish to inject 'Laminas\Diactoros\ConfigProv
4266
4367
Type `0` to select `[0] Do not inject`.
4468
45-
> We choose `0` because Dotkernel includes its own ConfigProvider, which already contains the prompted configurations.
46-
> If you choose `[1] config/config.php`, an extra `ConfigProvider` will be injected.
69+
> If you choose `1`, an extra `ConfigProvider` will be injected, which may return an error for packages you add in the future.
70+
> Choosing `0` prevents duplicate ConfigProvider registrations, as Dotkernel already includes its own.
4771
4872
The next question is:
4973
@@ -53,20 +77,29 @@ Type `y` here, and hit `enter` to complete this stage.
5377
5478
## Development mode
5579
56-
If you're installing the project for development, make sure you have development mode enabled by running:
80+
Normally, a new project starts in development mode to prevent caching certain files in the `data/cache` folder.
81+
Enable development mode by running:
5782
5883
```shell
5984
composer development-enable
6085
```
6186
62-
You can disable the development mode by running:
87+
The confirmation message should read:
88+
89+
```shell
90+
You are now in development mode.
91+
```
92+
93+
If you ever need to disable the development mode, run:
6394
6495
```shell
6596
composer development-disable
6697
```
6798
68-
You can check if you have development mode enabled by running:
99+
This command displays the development mode status:
69100
70101
```shell
71102
composer development-status
72103
```
104+
105+
You should see the message `Development mode is ENABLED` or `Development mode is DISABLED`.
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
# Configuration Files
22

3-
> The installation script should have already created the files mentioned on this page.
4-
> We mention them explicitly because you will need to visit them to fully configure your development environment.
3+
The post-update scripts from `composer.json` (under the key `post-update-cmd`) should have already created the files mentioned on this page.
4+
5+
> We mention these files explicitly because you will need to visit them to fully configure your development environment.
6+
> You will need to do the same for the production environment when you deploy your application.
57
68
## Prepare config files
79

8-
* duplicate `config/autoload/cors.local.php.dist` as `config/autoload/cors.local.php`
10+
The installation script will duplicate the following files:
11+
12+
* `config/autoload/cors.local.php.dist` as `config/autoload/cors.local.php`.
913

1014
> If your API is consumed by another application, make sure to configure the `allowed_origins` variable.
15+
> Normally, the other configuration items in `cors.local.php` should be left as-is.
16+
> If you need to tweak them, visit the [CORS tutorial](https://docs.dotkernel.org/api-documentation/v7/tutorials/cors/).
17+
18+
* `config/autoload/local.php.dist` as `config/autoload/local.php`.
1119

12-
* duplicate `config/autoload/local.php.dist` as `config/autoload/local.php`
20+
> `local.php` is the main configuration file for your application.
21+
> It contains the database connection parameters, the API key, and other configuration items.
1322
14-
* duplicate `config/autoload/mail.local.php.dist` as `config/autoload/mail.local.php`
23+
* `config/autoload/mail.local.php` from the `dot-mail` package installed in the `vendor` folder.
1524

16-
> If your API sends emails, make sure to fill in SMTP connection params
25+
> If your API sends emails, you also need to configure the `mail` key.
26+
> Most often, you will be using either `Sendmail` or `SMTP` to send emails.
27+
> If you opt for `SMTP`, ake sure to configure the SMTP connection parameters under the `smtp_options` key.
1728
18-
* **optional**: to run/create tests, duplicate `config/autoload/local.test.php.dist` as `config/autoload/local.test.php`
29+
* `config/autoload/local.test.php.dist` as `config/autoload/local.test.php` to run and create tests.
1930

2031
> This creates a new in-memory database that your tests will run on.

0 commit comments

Comments
 (0)