Install the Package
composer require 20steps/oauth2-php
Ensure symfony/http-foundation is also installed (dependency):
composer require symfony/http-foundation
Basic Server Initialization
Create a middleware to handle OAuth2 requests (e.g., app/Http/Middleware/OAuth2Server.php):
<?php
namespace App\Http\Middleware;
use League\OAuth2\Server\ResourceServer;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class OAuth2Server
{
public function handle(Request $request, \Closure $next)
{
$server = new \League\OAuth2\Server\ResourceServer(
$this->getPrivateKey(),
$this->getEncryptionKey(),
$this->getTokenRepository(),
$this->getScopeRepository()
);
try {
$request = $server->validateAuthenticatedRequest($request);
return $next($request);
} catch (\League\OAuth2\Server\Exception\OAuthServerException $exception) {
return new Response($exception->generateHttpResponse()->getContent(), $exception->generateHttpResponse()->getStatusCode());
}
}
// Implement methods to return keys, repositories, etc.
}
Register Middleware
Add the middleware to Laravel’s HTTP kernel (app/Http/Kernel.php):
protected $middleware = [
// ...
\App\Http\Middleware\OAuth2Server::class,
];
First Use Case: Protect an API Endpoint Annotate a controller method with the middleware (or apply globally):
use App\Http\Middleware\OAuth2Server;
class ProtectedController extends Controller
{
public function sensitiveData(OAuth2Server $middleware)
{
return response()->json(['data' => 'Secret info']);
}
}
src/: Core OAuth2 server logic (e.g., ResourceServer, GrantType, TokenRepository).tests/: Test cases for validation, token generation, and error handling.README.md: Focus on the "Usage" section for server/client setup.Middleware Integration Use the middleware to validate incoming requests before processing:
// app/Http/Middleware/OAuth2Server.php
public function handle($request, \Closure $next)
{
$server = new \League\OAuth2\Server\ResourceServer(
$this->getPrivateKey(),
$this->getEncryptionKey(),
$this->getTokenRepository()
);
try {
$request = $server->validateAuthenticatedRequest($request);
$request->attributes->add(['oauth_user' => $this->getUserFromToken($request)]);
return $next($request);
} catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
return response()->json(['error' => $e->getMessage()], $e->getHttpStatusCode());
}
}
Token Repository
Implement a custom repository to fetch tokens from Laravel’s database (e.g., app/Repositories/OAuth2TokenRepository.php):
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
class OAuth2TokenRepository implements AccessTokenRepositoryInterface
{
public function getAccessToken($tokenId)
{
return \App\Models\OAuthToken::find($tokenId);
}
// Implement other required methods...
}
Scope Management
Define scopes in a Laravel model (e.g., app/Models/OAuthScope.php) and inject into the server:
$scopeRepository = new \League\OAuth2\Server\Repositories\ScopeRepository(
\App\Models\OAuthScope::all()->pluck('id')->toArray(),
\App\Models\OAuthScope::all()->keyBy('id')
);
Grant Types Extend the library to support custom grant types (e.g., password grant):
use League\OAuth2\Server\Grant\PasswordGrant;
$grant = new PasswordGrant(
$this->getClientRepository(),
$this->getUserRepository(),
$this->getAccessTokenRepository(),
$this->getRefreshTokenRepository(),
$this->getScopeRepository()
);
Laravel Service Providers Bind repositories and configurations in a service provider:
public function register()
{
$this->app->singleton(\League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface::class, function ($app) {
return new \App\Repositories\OAuth2TokenRepository();
});
}
Database Schema Use migrations to create tables for clients, tokens, and scopes:
php artisan make:migration create_oauth_clients_table
php artisan make:migration create_oauth_access_tokens_table
Testing
Mock the ResourceServer in PHPUnit tests:
$server = $this->createMock(\League\OAuth2\Server\ResourceServer::class);
$server->method('validateAuthenticatedRequest')->willReturn($request);
Draft Version Mismatch
Token Repository Requirements
AccessTokenRepository must implement all abstract methods (e.g., getAccessToken, persistAccessTokenEntity, revokeAccessToken). Missing methods will throw BadMethodCallException.League\OAuth2\Server\Repositories\AccessTokenRepository and implement all methods.Encryption Key Format
InvalidArgumentException..env:
OAUTH_ENCRYPTION_KEY=your_raw_256_bit_key_here
Scope Validation
strtolower()) in both client and server.Middleware Order
VerifyCsrfToken middleware to avoid CSRF conflicts with token validation.app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ...
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\OAuth2Server::class,
],
];
Enable Verbose Errors Configure the server to return detailed error messages in development:
$server = new \League\OAuth2\Server\ResourceServer(
$privateKey,
$encryptionKey,
$tokenRepository,
$scopeRepository,
[
'error_details_enabled' => true, // Show detailed errors
'skip_default_error_handlers' => false,
]
);
Log Token Validation Add logging to track token validation attempts:
try {
$request = $server->validateAuthenticatedRequest($request);
\Log::info('Token validated successfully', ['token' => $request->bearerToken()]);
} catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
\Log::error('Token validation failed', ['error' => $e->getMessage()]);
}
Test with Postman/cURL Use tools like Postman to manually test OAuth2 flows:
curl -X POST \
-H "Authorization: Basic base64(client_id:client_secret)" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=user&password=pass" \
http://your-app.test/oauth/token
use League\OAuth2\Server\Grant\AbstractGrant;
class CustomGrant extends AbstractGrant
How can I help you explore Laravel packages today?