## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require cast1el/oauth-server-bundle
Register the bundle in config/bundles.php:
return [
// ...
Cast1el\OAuthServerBundle\Cast1elOAuthServerBundle::class => ['all' => true],
];
Configuration:
Update config/packages/cast1el_oauth_server.yaml (create if missing):
cast1el_oauth_server:
db_driver: orm
query_parameters:
client_id: client_id
client_secret: client_secret
scope: scope
user_id: user_id
access_token:
ttl: 3600
refresh_token:
ttl: 2592000
First Use Case:
Generate a Client: Use the provided command to create an OAuth client:
php bin/console fos:oauth-server:create-client
This creates a client entry in your database (e.g., oauth2_client).
Test the Authorization Flow: Redirect users to:
/oauth/v2/auth?client_id={client_id}&redirect_uri={redirect_uri}&response_type=code&scope=read
Exchange the authorization code for an access token:
curl -X POST -d "grant_type=authorization_code&code={code}&redirect_uri={redirect_uri}&client_id={client_id}&client_secret={client_secret}" http://your-app/oauth/v2/token
Client Management:
Dynamic Client Creation: Extend the bundle by creating a custom command or controller to generate clients programmatically:
use Cast1el\OAuthServerBundle\Entity\Client;
use Doctrine\ORM\EntityManagerInterface;
$client = new Client();
$client->setRandomId();
$client->setSecret('your-secret');
$client->setRedirectUris(['https://your-app/callback']);
$em->persist($client);
$em->flush();
Client Scopes:
Define scopes in the cast1el_oauth_server.yaml:
cast1el_oauth_server:
scopes: { read: 'Read access', write: 'Write access' }
Attach scopes to clients via the Client entity or during runtime.
Token Handling:
Access Token Storage:
Customize token storage by implementing Cast1el\OAuthServerBundle\Storage\TokenStorageInterface:
class CustomTokenStorage implements TokenStorageInterface {
public function findToken($token) { /* ... */ }
public function saveToken(Token $token) { /* ... */ }
}
Register it in services:
services:
Cast1el\OAuthServerBundle\Storage\TokenStorageInterface: '@App\Storage\CustomTokenStorage'
Token Validation: Validate tokens in controllers or services:
use Cast1el\OAuthServerBundle\Security\Token\OAuthToken;
$token = $this->get('security.token_storage')->getToken();
if ($token instanceof OAuthToken) {
$user = $token->getUser();
$client = $token->getClient();
}
Resource Servers:
oauth_token firewall in security.yaml:
security:
firewalls:
api:
pattern: ^/api
oauth_token:
check_path: /oauth/v2/token/validate
service: Cast1el\OAuthServerBundle\Security\Token\OAuthToken
Validate tokens in controllers:
public function secureAction(Request $request) {
$token = $this->get('security.token_storage')->getToken();
if (!$token instanceof OAuthToken) {
throw new \RuntimeException('Invalid token');
}
// Proceed with authorized logic
}
Integration with FOSUserBundle:
User entity:
use Cast1el\OAuthServerBundle\Entity\UserInterface as OAuthUserInterface;
class User implements OAuthUserInterface {
public function getOAuthUserId() { /* ... */ }
}
Configure the bundle to use FOSUserBundle's user provider:
cast1el_oauth_server:
user_provider: fos_user.user_provider.username_email
Database Schema:
oauth2_client, oauth2_access_token, oauth2_refresh_token). If using Doctrine ORM, ensure migrations are run:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
php bin/console doctrine:schema:update --force
Token Expiry:
3600 seconds) and refresh tokens (2592000 seconds) may not suit all use cases. Adjust in config:
cast1el_oauth_server:
access_token:
ttl: 7200 # 2 hours
refresh_token:
ttl: 5184000 # 60 days
CSRF Protection:
# config/packages/security.yaml
security:
access_control:
- { path: ^/oauth/v2/token, roles: [IS_AUTHENTICATED_ANONYMOUSLY], methods: [POST], require_csrf: true }
Scope Validation:
$scopes = explode(' ', $token->getScope());
if (!in_array('read', $scopes)) {
throw new \RuntimeException('Insufficient scope');
}
Enable Debugging:
config/packages/dev/cast1el_oauth_server.yaml:
cast1el_oauth_server:
debug: true
var/log/dev.log.Token Validation Errors:
invalid_grant: Invalid authorization code or refresh token.invalid_client: Incorrect client_id or client_secret.unsupported_grant_type: Wrong grant_type (e.g., password when using authorization code flow).Redirect URI Mismatch:
redirect_uri in the authorization request matches the one registered in the client. The bundle throws an exception if they don’t match.Custom Grant Types:
Cast1el\OAuthServerBundle\Grant\GrantTypeInterface:
class CustomGrant implements GrantTypeInterface {
public function getGrantType() { return 'custom'; }
public function authenticate(Request $request) { /* ... */ }
}
services:
App\Grant\CustomGrant:
tags: ['cast1el_oauth_server.grant_type']
Custom User Providers:
Cast1el\OAuthServerBundle\User\UserProviderInterface for custom user lookups:
class CustomUserProvider implements UserProviderInterface {
public function loadUserByOAuthUserId($id) { /* ... */ }
}
cast1el_oauth_server.yaml:
cast1el_oauth_server:
user_provider: 'App\User\CustomUserProvider'
Event Listeners:
oauth.token.create) to log or modify token creation:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Cast1el\OAuthServerBundle\Event\TokenEvent;
class OAuthEventSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
TokenEvent::CREATE => 'onTokenCreate',
];
}
public function onTokenCreate(TokenEvent $event) {
// Modify token or log
}
}
services:
App\Event\OAuthEventSubscriber:
tags: ['kernel.event_subscriber']
API Documentation:
/**
* @OA\Post(
* path="/oauth/v2/token",
* summary
How can I help you explore Laravel packages today?