Since this is a Symfony bundle, Laravel integration requires Symfony’s HTTP Kernel or a bridge like symfony/console-bridge. For Laravel 8/9, use spatie/laravel-symfony-support to bridge the gap.
Install Dependencies
composer require amashukov/oauth-server-bundle friendsofsymfony/oauth2-php
Configure Kernel (if using Symfony Kernel)
Extend HttpKernel in config/kernel.php (if using Symfony components):
$kernel = new \Symfony\Component\HttpKernel\Kernel(
'dev',
true
);
$kernel->boot();
Register Bundle (Symfony-style)
In config/bundles.php (Symfony) or manually bootstrap in Laravel’s AppServiceProvider:
$this->app->register(new \Amashukov\OAuthServerBundle\OAuthServerBundle());
First OAuth Endpoint
Define a route to trigger the OAuth server (e.g., /oauth/v2/token):
Route::post('/oauth/v2/token', [OAuthController::class, 'token']);
Ensure the route uses Symfony’s Request/Response (or convert Laravel’s Request):
use Symfony\Component\HttpFoundation\Request;
$request = Request::createFromGlobals();
Basic Configuration
In config/packages/oauth_server.yaml (Symfony) or config/oauth.php (Laravel):
oauth_server:
grant_types: [password, refresh_token]
access_token_lifetime: 3600
refresh_token_lifetime: 86400
Password Grant Flow
Use the password grant type for client credentials + user credentials:
$client = new \OAuth2\Server\ResourceServer(
new \OAuth2\Server\Storage\Memory(),
new \OAuth2\Server\CryptKey('your_private_key', 'RSA')
);
$request = Request::create('/oauth/v2/token', 'POST', [
'grant_type' => 'password',
'client_id' => 'your_client_id',
'client_secret' => 'your_client_secret',
'username' => 'user@example.com',
'password' => 'password123',
]);
$response = $client->handleTokenRequest($request);
Refresh Tokens
Reuse the same endpoint with grant_type=refresh_token:
$request->request->set('grant_type', 'refresh_token');
$request->request->set('refresh_token', 'old_refresh_token');
User Provider Bridge
Extend Symfony’s UserProviderInterface to work with Laravel’s User model:
use Symfony\Component\Security\Core\User\UserProviderInterface;
class LaravelUserProvider implements UserProviderInterface {
public function loadUserByUsername($username) {
return User::where('email', $username)->firstOrFail();
}
// ... other methods
}
Guard Integration
Use Symfony’s UserCheckerInterface to validate users:
$userChecker = new \Symfony\Component\Security\Core\User\UserChecker();
$userChecker->checkPreAuth($user);
Extend the bundle’s GrantType logic:
use OAuth2\Server\GrantType\GrantTypeInterface;
class CustomGrantType implements GrantTypeInterface {
public function validateRequest(OAuth2\RequestInterface $request) {
// Custom validation (e.g., JWT, custom claims)
}
public function issueAccessToken(OAuth2\Server $server, $username, $scope) {
// Custom token generation
}
}
Register in config:
oauth_server:
grant_types:
- custom_grant
Symfony Dependency Hell
DependencyInjection and HttpFoundation. In Laravel, mock these:
$container = new \Symfony\Component\DependencyInjection\ContainerBuilder();
$container->register('request_stack', RequestStack::class);
Token Storage
Memory storage is not persistent. Use Doctrine/DBAL:
oauth_server:
storage:
class: OAuth2\Server\Storage\Pdo
options:
dsn: 'mysql:host=localhost;dbname=oauth'
CSRF Protection
CsrfTokenManager may conflict with Laravel’s. Disable in config:
oauth_server:
csrf_protection: false
Deprecated dev-master
friendsofsymfony/oauth2-php is pinned to dev-master. Lock to a stable version:
composer require friendsofsymfony/oauth2-php:^1.0
Enable Verbose Logging
Configure Monolog in Symfony or Laravel’s monolog.php:
'handlers' => [
new \Monolog\Handler\StreamHandler(__DIR__.'/../var/log/oauth.log', \Monolog\Logger::DEBUG),
],
Token Validation Errors
Check the error and error_description fields in responses. Common issues:
invalid_grant: Expired refresh token or invalid credentials.unsupported_grant_type: Missing or invalid grant_type.Custom User Entity
Override the UserEntity class to map to Laravel’s User:
class LaravelUserEntity extends \OAuth2\Server\Entity\UserEntity {
public static function createFromLaravelUser(User $user) {
return new self($user->id, $user->email, $user->password);
}
}
Scope Management
Extend ScopeEntity for role-based scopes:
class CustomScopeEntity extends \OAuth2\Server\Entity\ScopeEntity {
public function __construct($identifier, array $scopes = []) {
parent::__construct($identifier, ['read', 'write', ...$scopes]);
}
}
Event Listeners
Hook into OAuth events (e.g., token_created):
use OAuth2\Server\Event\TokenCreatedEvent;
$dispatcher->addListener('token_created', function (TokenCreatedEvent $event) {
// Log or modify token data
});
Route Caching
Use php artisan route:cache after adding OAuth routes to avoid conflicts with Laravel’s middleware.
Middleware Order
Place OAuth middleware after Laravel’s auth middleware to ensure user validation:
Route::middleware(['auth:sanctum', 'oauth'])->post('/oauth/token', [OAuthController::class, 'token']);
Testing
Use Laravel’s HttpTests with Symfony’s Client:
$client = static::createClient();
$client->request('POST', '/oauth/v2/token', [
'grant_type' => 'password',
'client_id' => 'test',
'client_secret' => 'test',
'username' => 'user@example.com',
'password' => 'password',
]);
How can I help you explore Laravel packages today?