Quickstart Guide
This guide walks through creating a fresh Osumi Framework 9.10 project, installing the token plugin, generating an action and a Middleware with the CLI, creating a model, defining a protected route and returning JSON.
By the end you will have:
- A new Osumi Framework application
- The OToken plugin installed
- A working
LoginMiddleware - A
Usermodel - An authenticated
/api/get-usersendpoint returning JSON
All examples assume PHP 8.5+ and declare(strict_types=1);.
1. Create a New Project
composer create-project osumionline/new myapp
2. Install the OToken Plugin
composer require osumionline/plugin-token
The application can then use:
use Osumi\OsumiFramework\Plugins\OToken;
3. Remove Example Data
php of reset
This keeps the standard application structure while removing example functionality.
4. Create a New Action
php of add --option action --name api/getUsers --url /api/get-users --type json
This creates files under:
src/Api/GetUsers/
including:
src/Api/GetUsers/GetUsersComponent.php
src/Api/GetUsers/GetUsersTemplate.json
and, unless disabled, the corresponding route entry.
The generated namespace is:
namespace Osumi\OsumiFramework\App\Api\GetUsers;
5. Create a Login Middleware
Generate the Middleware:
php of add --option middleware --name Login
This creates:
src/Middleware/LoginMiddleware.php
Replace its contents with your authentication logic.
Example:
<?php
declare(strict_types=1);
namespace Osumi\OsumiFramework\App\Middleware;
use Osumi\OsumiFramework\Core\OCore;
use Osumi\OsumiFramework\Core\OMiddleware;
use Osumi\OsumiFramework\Plugins\OToken;
final class LoginMiddleware {
/**
* Validate the Authorization token and publish the authenticated user ID.
*
* @param string $phase Current middleware phase.
* @param array<string, mixed> $data Current middleware pipeline data.
*
* @return array<string, mixed> Middleware result.
*/
public static function handle(
string $phase,
array $data
): array {
if ($phase !== OMiddleware::PHASE_BEFORE) {
return [];
}
global $core;
if (
!($core instanceof OCore) ||
$core->config === null
) {
return [
'stop' => true,
'status_code' => 500,
'message' => 'Framework configuration is not available.'
];
}
$headers = $data['headers'] ?? [];
if (!is_array($headers)) {
return [
'stop' => true,
'status_code' => 401,
'message' => 'Unauthorized'
];
}
$normalized_headers = array_change_key_case(
$headers,
CASE_LOWER
);
$authorization = $normalized_headers['authorization']
?? null;
if (
!is_string($authorization) ||
$authorization === ''
) {
return [
'stop' => true,
'status_code' => 401,
'message' => 'Unauthorized'
];
}
$secret = $core->config->getExtra(
'secret'
);
if (
!is_string($secret) ||
$secret === ''
) {
return [
'stop' => true,
'status_code' => 500,
'message' => 'Token secret is not configured.'
];
}
$token = new OToken(
$secret
);
if (!$token->checkToken($authorization)) {
return [
'stop' => true,
'status_code' => 401,
'message' => 'Unauthorized'
];
}
return [
'context' => [
'id' => (int) $token->getParam('id')
]
];
}
}
This Middleware:
- Runs in the
beforephase. - Reads the
Authorizationheader. - Validates the token.
- Stops the request with HTTP 401 when authentication fails.
- Publishes the authenticated user ID as
Login.id.
6. Create the User Model
Create:
src/Model/User.php
Example:
<?php
declare(strict_types=1);
namespace Osumi\OsumiFramework\App\Model;
use Osumi\OsumiFramework\ORM\OCreatedAt;
use Osumi\OsumiFramework\ORM\OField;
use Osumi\OsumiFramework\ORM\OModel;
use Osumi\OsumiFramework\ORM\OPK;
use Osumi\OsumiFramework\ORM\OUpdatedAt;
class User extends OModel {
#[OPK(
comment: "Unique ID for a user"
)]
public ?int $id = null;
#[OField(
comment: "User name",
max: 100,
nullable: false
)]
public ?string $name = null;
#[OField(
comment: "User email",
max: 100,
nullable: false
)]
public ?string $email = null;
#[OCreatedAt(
comment: "Record creation date"
)]
public ?string $created_at = null;
#[OUpdatedAt(
comment: "Record update date"
)]
public ?string $updated_at = null;
}
7. Protect the API Route
Create or edit:
src/Routes/Api.php
Example:
<?php
declare(strict_types=1);
use Osumi\OsumiFramework\App\Api\GetUsers\GetUsersComponent;
use Osumi\OsumiFramework\App\Middleware\LoginMiddleware;
use Osumi\OsumiFramework\Core\OMiddleware;
use Osumi\OsumiFramework\Routing\ORoute;
ORoute::get(
'/api/get-users',
GetUsersComponent::class,
[
OMiddleware::PHASE_BEFORE => [
LoginMiddleware::class
]
]
);
The component is only executed when the Middleware completes without stop.
8. Create a Model Component
php of add --option modelComponent --name User
This generates:
src/Component/Model/User/UserComponent.php
src/Component/Model/User/UserTemplate.php
src/Component/Model/UserList/UserListComponent.php
src/Component/Model/UserList/UserListTemplate.php
9. Modify the Generated Action
Open:
src/Api/GetUsers/GetUsersComponent.php
Example:
<?php
declare(strict_types=1);
namespace Osumi\OsumiFramework\App\Api\GetUsers;
use Osumi\OsumiFramework\App\Component\Model\UserList\UserListComponent;
use Osumi\OsumiFramework\App\Model\User;
use Osumi\OsumiFramework\Core\OComponent;
use Osumi\OsumiFramework\Web\ORequest;
class GetUsersComponent extends OComponent {
public string $status = 'ok';
public ?UserListComponent $list = null;
/**
* Load users for an authenticated request.
*
* @param ORequest $req Current request.
*
* @return void
*/
public function run(ORequest $req): void {
$id_user = $req->getMiddlewareValue(
'Login',
'id'
);
$this->list = new UserListComponent();
if (!is_int($id_user)) {
$this->status = 'error';
$this->list->list = [];
return;
}
$this->list->list = User::where([]);
}
}
The value published by LoginMiddleware is available through:
$req->getMiddlewareValue(
'Login',
'id'
);
10. Modify the JSON Template
Open:
src/Api/GetUsers/GetUsersTemplate.json
Example:
{
"status": {{ status | plain }},
"users": [
{{ list }}
]
}
Use the plain pipe when the original string should be preserved without URL encoding.
11. Test the Endpoint
curl -X GET http://localhost:8000/api/get-users \
-H "Authorization: YOUR_TOKEN_HERE"
With a valid token, the protected component runs.
With a missing or invalid token, LoginMiddleware stops the request and the framework returns a typed JSON error response with HTTP 401.
12. Summary
This quickstart covered:
- Creating a project
- Installing OToken
- Resetting example data
- Generating an API action
- Creating a native Middleware
- Publishing authenticated context
- Protecting a route with
before - Reading Middleware context through
ORequest - Creating a model and Model Component
- Returning JSON
You now have the current authentication flow, introduced in 9.9 using Middlewares instead of legacy Filters.