Installation
composer require averor/oauth-server-bundle
Add to config/bundles.php (Symfony):
return [
// ...
Averor\OAuthServerBundle\AverorOAuthServerBundle::class => ['all' => true],
];
Configuration
Define OAuth endpoints in config/packages/averor_oauth_server.yaml:
averor_oauth_server:
token_endpoint: /oauth/token
authorize_endpoint: /oauth/authorize
client_class: App\Entity\OAuthClient
access_token_class: App\Entity\AccessToken
refresh_token_class: App\Entity\RefreshToken
auth_code_class: App\Entity\AuthCode
First Use Case
Create a client entity (e.g., OAuthClient) with required fields:
// src/Entity/OAuthClient.php
use Averor\OAuthServerBundle\Entity\ClientInterface;
class OAuthClient implements ClientInterface {
// Required fields: id, secret, redirectUri, name
}
Register the entity as a Doctrine resource and clear cache:
php bin/console doctrine:schema:update --force
Test the Token Endpoint
Use curl to request a token:
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET" \
http://your-app/oauth/token
$client = $this->getDoctrine()->getRepository(OAuthClient::class)->find('client_id');
$token = $this->oauthServer->getAccessToken($client, 'client_credentials');
$tokenData = json_decode($token->jsonSerialize(), true);
$accessToken = $tokenData['access_token'];
/oauth/authorize with response_type=code.$authCode = $this->oauthServer->getAuthCodeRepository()->find($code);
$token = $this->oauthServer->getAccessToken($authCode->getClient(), 'authorization_code', [
'code' => $code,
'redirect_uri' => $authCode->getRedirectUri(),
]);
$user = $this->getUser(); // Symfony UserInterface
$client = $this->getDoctrine()->getRepository(OAuthClient::class)->find('client_id');
$token = $this->oauthServer->getAccessToken($client, 'password', [
'username' => $user->getUsername(),
'password' => $password,
]);
OAuthTokenAuthenticator to validate access tokens:
# config/packages/security.yaml
firewalls:
main:
stateless: true
provider: oauth_token
custom_authenticators:
- Averor\OAuthServerBundle\Security\OAuthTokenAuthenticator
providers:
oauth_token:
entity:
class: App\Entity\User
property: oauthId
Scope entity or use a trait:
use Averor\OAuthServerBundle\Entity\ScopeInterface;
class CustomScope implements ScopeInterface {
public function getIdentifier(): string { return 'custom_scope'; }
}
averor_oauth_server:
scopes:
- { identifier: 'read', description: 'Read access' }
- { identifier: 'write', description: 'Write access' }
GrantTypeInterface:
use Averor\OAuthServerBundle\Grant\GrantTypeInterface;
class CustomGrant implements GrantTypeInterface {
public function getIdentifier(): string { return 'custom'; }
public function validate(array $params, ClientInterface $client): bool { /* ... */ }
public function generateToken(array $params, ClientInterface $client): AccessTokenInterface { /* ... */ }
}
services:
App\Grant\CustomGrant:
tags: [averor_oauth_server.grant_type]
Class [App\Entity\AccessToken] does not exist.Client, AccessToken, RefreshToken, AuthCode) are:
ClientInterface, AccessTokenInterface, etc.).id, client_id, expiresAt).php bin/console debug:container averor_oauth_server to verify service binding.redirect_uri_mismatch during authorization.redirect_uri in the authorize request matches the client’s registered URI.https://example.com/callback).require_redirect_uri_registration in averor_oauth_server.yaml:
averor_oauth_server:
require_redirect_uri_registration: true
access_token_lifetime and refresh_token_lifetime in config (default: 3600/2592000 seconds):
averor_oauth_server:
access_token_lifetime: 7200 # 2 hours
refresh_token_lifetime: 2592000 # 30 days
getLifetime() in your AccessToken entity.state parameter not validated in authorize flow.averor_oauth_server:
authorize:
enable_csrf: true
state parameter in authorize requests.AccessToken entity’s getScopes() method.scope parameter in token requests (e.g., scope=read write).averor_oauth_server:
debug: true
Logs will appear in var/log/dev.log.
Use Symfony’s Dumper in a controller:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
dump($request->query->all(), $request->request->all());
GET http://your-app/oauth/authorize?
response_type=code&
client_id=CLIENT_ID&
redirect_uri=REDIRECT_URI&
scope=read&
state=random_state
POST http://your-app/oauth/token
Body: grant_type=authorization_code&code=AUTH_CODE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET
StorageInterface for non-Doctrine storage (e.g., Redis):
use Averor\OAuthServerBundle\Storage\StorageInterface;
class RedisStorage implements StorageInterface {
public function findClient($clientId) { /* ... */ }
public function findAccessToken($token) { /* ... */ }
// ... other methods
}
services:
App\Storage\RedisStorage:
tags: [averor_oauth_server.storage]
How can I help you explore Laravel packages today?