blackcube / yii-oauth2
PHP 8.3+ OAuth2/JWT toolbox for Yii3 framework with multi-population support
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/blackcube/yii-oauth2
Requires
- php: >=8.3
- bshaffer/oauth2-server-php: ^v1.14
- lcobucci/jwt: ^5.6
- psr/clock: ^1.0
- psr/http-message: ^1.0 || ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- yiisoft/yii-http: ^1.1
Requires (Dev)
- codeception/codeception: ^5.3
- codeception/module-asserts: ^3.3
- codeception/module-db: ^3.2
- httpsoft/http-message: ^1.1
- vlucas/phpdotenv: ^v5.6
- yiisoft/active-record: ^1.0
- yiisoft/cache-file: ^3.2
- yiisoft/db: ^2.0
- yiisoft/db-migration: ^2.0
- yiisoft/db-mysql: ^2.0
- yiisoft/di: ^1.4
- yiisoft/factory: ^1.3
- yiisoft/test-support: ^3.1
This package is auto-updated.
Last update: 2026-01-24 17:46:04 UTC
README
PHP 8.3+ OAuth2/JWT toolbox for Yii3 framework with multi-population support based on BShaffer oauth2 server.
Installation
composer require blackcube/yii-oauth2
Requirements
- PHP >= 8.3
Based On
- bshaffer/oauth2-server-php - OAuth2 engine
- lcobucci/jwt - JWT handling
Philosophy
This package is a toolbox, not a turnkey solution. It provides interfaces and tools, never concrete implementations. The application that integrates it decides everything: storage, tables, business logic, routes.
Principles:
- Zero imposed tables
- Zero imposed storage (no MySQL/Redis in the package)
- Multi-population support (admin ≠ customer in the same app)
- DRY: scopes can be derived from an existing system (RBAC, config, API...)
Configuration
params.php
return [ 'blackcube/yii-oauth2' => [ 'algorithm' => 'RS256', 'accessTokenTtl' => 3600, // 1h 'refreshTokenTtl' => 2592000, // 30 days 'populations' => [ 'admin' => [ 'algorithm' => 'RS512', // Override base 'accessTokenTtl' => 7200, // 2h for admin 'issuer' => 'myapp-admin', 'audience' => 'myapi', // Entity classes (your app provides these) 'userClass' => \App\Oauth2\Admin\AdminUser::class, 'clientClass' => \App\Oauth2\Admin\AdminClient::class, 'refreshTokenClass' => \App\Oauth2\Admin\AdminRefreshToken::class, 'scopeProvider' => \App\Oauth2\Admin\RbacScopeProvider::class, 'cypherKeyClass' => \App\Oauth2\Admin\AdminCypherKey::class, // Routes 'routes' => [ 'token' => [ 'pattern' => '/oauth2/admin/token', 'methods' => ['POST'], ], 'revoke' => [ 'pattern' => '/oauth2/admin/revoke', 'methods' => ['POST'], ], ], ], 'customer' => [ 'issuer' => 'myapp-customer', 'audience' => 'shop', 'userClass' => \App\Oauth2\Customer\CustomerUser::class, 'clientClass' => \App\Oauth2\Customer\CustomerClient::class, 'refreshTokenClass' => \App\Oauth2\Customer\CustomerRefreshToken::class, 'scopeProvider' => \App\Oauth2\Customer\CustomerScopeProvider::class, 'cypherKeyClass' => \App\Oauth2\Customer\CustomerCypherKey::class, 'routes' => [ 'token' => [ 'pattern' => '/oauth2/token', 'methods' => ['POST'], ], ], 'allowedGrants' => ['password', 'refresh_token'], ], ], ], ];
Interfaces to Implement
Your application must provide implementations for these interfaces per population:
| Interface | Purpose |
|---|---|
UserInterface |
User entity with getId, getIdentifier, queryById, queryByIdentifier, queryByIdentifierAndPassword |
ClientInterface |
OAuth2 client entity with getId, getSecret, queryById, validateSecret |
RefreshTokenInterface |
Refresh token entity with save, revoke, queryByToken |
ScopeProviderInterface |
Available scopes, scopes per client |
CypherKeyInterface |
Signing keys (RSA/HMAC) with queryById, queryDefault |
Supported Grants
| Grant | Usage |
|---|---|
| password | User login (mobile, SPA legacy) |
| client_credentials | Service to Service (Node → PHP) |
| authorization_code + PKCE | Mobile, modern SPAs |
| refresh_token | Token renewal |
JWT Claims
{
"sub": "123",
"iss": "myapp-admin",
"aud": "myapi",
"exp": 1234567890,
"iat": 1234567800,
"scopes": ["category", "node", "order"]
}
| Claim | Description |
|---|---|
| sub | Subject - User ID |
| iss | Issuer - Identifies the population |
| aud | Audience - Token target |
| exp | Expiration timestamp |
| iat | Issued at timestamp |
| scopes | Granted scopes |
Algorithms
| Algorithm | Type | Usage |
|---|---|---|
| RS256 | Asymmetric | Default - Multi-services |
| RS384 | Asymmetric | More secure than RS256 |
| RS512 | Asymmetric | Maximum security |
| HS256 | Symmetric | Simple, shared secret |
| HS384 | Symmetric | More secure than HS256 |
| HS512 | Symmetric | Maximum symmetric security |
Recommendation: RS256/RS384/RS512 if multiple services validate tokens. HS* only if everything stays in the same PHP process.
Key Generation
RSA (RS*)
# RS256/RS384/RS512 - 2048 bits key (minimum) openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout -out public.pem # RS512 - 4096 bits key (recommended) openssl genrsa -out private.pem 4096 openssl rsa -in private.pem -pubout -out public.pem
HMAC (HS*)
# Random 256 bits secret minimum openssl rand -base64 32 > secret.key
Middleware Usage
use Blackcube\Oauth2\Middleware\JwtValidatorMiddleware; // In your route configuration Route::get('/api/protected') ->middleware(JwtValidatorMiddleware::class) ->action([ProtectedController::class, 'index']);
The middleware injects these attributes into the request:
jwt- Full claims arrayuserId- Subject (sub claim)population- Issuer (iss claim)scopes- Granted scopes array
What This Package Does NOT Do
- Impose tables
- Impose storage (MySQL, Redis, etc.)
- Manage RBAC
- Decide routes
- Impose user/client structure
- Manage sessions
- Provide views (login, authorize, etc.)
License
BSD-3-Clause. See LICENSE.md.
Author
Philippe Gaultier philippe@blackcube.io