dbp/relay-authorization-bundle
Install the Bundle
composer require dbp/relay-authorization-bundle
Ensure your config/bundles.php includes:
return [
// ...
DigitalBlueprint\RelayAuthorizationBundle\DbpRelayAuthorizationBundle::class => ['all' => true],
];
Database Migration
Run migrations to create the required tables (groups, grants, etc.):
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case: Granting Access
Inject the AuthorizationManager service and define a grant:
use DigitalBlueprint\RelayAuthorizationBundle\Authorization\AuthorizationManager;
class MyController {
public function __construct(private AuthorizationManager $authManager) {}
public function index(): void {
$this->authManager->grant('group:admin', 'resource:dashboard', 'read');
}
}
Check Authorization Verify if a user (via group) has access:
$hasAccess = $this->authManager->check('group:admin', 'resource:dashboard', 'read');
Documentation First Review the ./docs for:
read, write, delete, admin).Group Management
$this->authManager->createGroup('group:editor', ['description' => 'Content Editors']);
$groups = $this->authManager->getGroups();
Grant-Based Authorization
resource:{type}:{id} (e.g., resource:post:123).$this->authManager->grantMultiple('group:admin', [
'resource:dashboard' => ['read', 'write'],
'resource:settings' => ['admin'],
]);
$this->authManager->revoke('group:admin', 'resource:dashboard', 'read');
Integration with Relay API
RelayAuthorizationChecker in controllers to gate API endpoints:
use DigitalBlueprint\RelayAuthorizationBundle\Relay\RelayAuthorizationChecker;
public function updatePost(RelayAuthorizationChecker $checker, int $id): void {
if (!$checker->check('group:admin', "resource:post:$id", 'write')) {
throw new AccessDeniedException();
}
// Proceed with update
}
Event-Driven Extensions
// config/services.yaml
DigitalBlueprint\RelayAuthorizationBundle\EventListener\AuthorizationListener:
tags:
- { name: kernel.event_listener, event: authorization.grant.created, method: onGrantCreated }
Custom Grant Types
GrantType enum or create a custom validator:
use DigitalBlueprint\RelayAuthorizationBundle\Authorization\GrantType;
// Add to config/packages/relay_authorization.yaml
relay_authorization:
custom_grant_types:
- 'publish'
- 'archive'
Resource Naming Collisions
resource:user vs. resource:user:1). Use resource:{type}:{id} strictly.APP_DEBUG=1) to verify queries:
$this->authManager->getGrant('group:admin', 'resource:dashboard');
Caching Quirks
php bin/console cache:clear
config/packages/relay_authorization.yaml:
relay_authorization:
cache_grants: false
Symfony Security Integration
RelayAuthorizationChecker for Relay-specific logic.use DigitalBlueprint\RelayAuthorizationBundle\Relay\RelayAuthorizationChecker;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class RelayVoter implements Voter {
public function __construct(private RelayAuthorizationChecker $checker) {}
public function vote(TokenInterface $token, $subject, array $attributes): bool {
$group = $token->getUser()->getGroup();
return $this->checker->check($group, $subject, 'read');
}
}
Migration Order
AuthorizationManager in code.Grant Inheritance
group:admin inherits from group:user), implement a custom resolver:
use DigitalBlueprint\RelayAuthorizationBundle\Authorization\AuthorizationManagerInterface;
class HierarchicalAuthorizationManager implements AuthorizationManagerInterface {
public function check(string $group, string $resource, string $grant): bool {
// Custom logic to check parent groups
return $this->fallbackManager->check($group, $resource, $grant) ||
$this->checkParentGroups($group, $resource, $grant);
}
}
Audit Logging
config/packages/relay_authorization.yaml:
relay_authorization:
audit_log: true
authorization_audit_log table.Performance
use DigitalBlueprint\RelayAuthorizationBundle\Authorization\AuthorizationManager;
class WarmupCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output): int {
$this->authManager->getAllGrants(); // Forces cache population
return Command::SUCCESS;
}
}
Testing
AuthorizationManagerTestCase base class for unit tests:
use DigitalBlueprint\RelayAuthorizationBundle\Tests\AuthorizationManagerTestCase;
class MyTest extends AuthorizationManagerTestCase {
public function testGrantCreation() {
$this->assertTrue($this->authManager->grant('group:test', 'resource:test', 'read'));
}
}
Relay API Integration
relay-server-template is configured to use the same database as your Symfony app. Share the DATABASE_URL in .env.Custom Resource Resolvers
use DigitalBlueprint\RelayAuthorizationBundle\Authorization\ResourceResolverInterface;
class CustomResourceResolver implements ResourceResolverInterface {
public function resolve(string $resource): ?string {
if (str_starts_with($resource, 'resource:post:')) {
$postId = substr($resource, 12);
return $this->postRepository->findActive($postId) ? $resource : null;
}
return $resource;
}
}
Register in services.yaml:
DigitalBlueprint\RelayAuthorizationBundle\Authorization\ResourceResolverInterface: '@custom_resource_resolver'
Bulk Operations
$entityManager = $this->authManager->getEntityManager();
$entityManager->beginTransaction();
try {
$this->authManager->grantMultiple('group:admin', [...]);
$entityManager->commit();
} catch (\Exception $e) {
$entityManager->rollBack();
throw $e;
}
How can I help you explore Laravel packages today?