openfga-laravel-rbac maintained by mvonline
OpenFGA Laravel RBAC
PHP and Laravel SDK for using OpenFGA as an RBAC and authorization service.
This package provides:
- A framework-agnostic PHP OpenFGA HTTP client
- Laravel auto-discovery, facades, config publishing, Gate integration, and middleware
- RBAC helper methods for roles, permissions, assignments, and common checks
- Advanced OpenFGA API support for contextual tuples, batch checks, list users, changes, assertions, stores, and authorization models
- Docker-friendly test workflow, so PHP does not need to be installed on the host machine
Requirements
- PHP
^8.1 - Composer
- OpenFGA server or OpenFGA-compatible endpoint
- Laravel
10,11, or12for Laravel-specific features
Installation
composer require mvonline/openfga-laravel-rbac
Laravel Setup
Publish the configuration file:
php artisan vendor:publish --tag=openfga-rbac-config
Configure your OpenFGA connection:
OPENFGA_API_URL=http://localhost:8080
OPENFGA_STORE_ID=01H...
OPENFGA_AUTHORIZATION_MODEL_ID=01H...
OPENFGA_TOKEN=
The package auto-registers these aliases in Laravel:
OpenFgafor the low-level OpenFGA clientOpenFgaRbacfor RBAC helper methods
OpenFGA Model Example
This model supports users, roles, a registry for listing roles and permissions, and a tenant resource.
model
schema 1.1
type user
type permission
type rbac
relations
define role: [role]
define permission: [permission]
type role
relations
define assignee: [user]
type tenant
relations
define admin: [user, role#assignee]
define member: [user, role#assignee] or admin
For resource-specific permissions, add relations to your resource types. Example:
type invoice
relations
define viewer: [user, role#assignee]
define editor: [user, role#assignee]
define owner: [user]
Laravel Usage
Low-Level Checks
use OpenFga;
$allowed = OpenFga::check(
'user:' . $user->id,
'viewer',
'invoice:' . $invoice->id,
);
RBAC Helpers
use OpenFgaRbac;
OpenFgaRbac::createRole('billing-admin');
OpenFgaRbac::createPermission('invoice.view');
OpenFgaRbac::assignRole($user->id, 'billing-admin');
OpenFgaRbac::grantRolePermission('billing-admin', 'viewer', 'invoice', $invoice->id);
if (OpenFgaRbac::can($user->id, 'viewer', 'invoice', $invoice->id)) {
// authorized
}
Role And Permission Queries
$roles = OpenFgaRbac::listRoles();
$permissions = OpenFgaRbac::listPermissions();
$userRoles = OpenFgaRbac::userRoles($user->id);
$roleUsers = OpenFgaRbac::usersAssignedToRole('billing-admin');
$rolePermissions = OpenFgaRbac::rolePermissions('billing-admin');
Any Or All Permission Checks
$canReadOrEdit = OpenFgaRbac::canAny($user->id, ['viewer', 'editor'], 'invoice', $invoice->id);
$canReadAndEdit = OpenFgaRbac::canAll($user->id, ['viewer', 'editor'], 'invoice', $invoice->id);
Laravel Middleware
Single check:
Route::get('/invoices/{invoice}', InvoiceController::class)
->middleware('openfga:viewer,invoice:{invoice}');
Any check can pass:
Route::get('/invoices/{invoice}', InvoiceController::class)
->middleware('openfga.any:owner:invoice:{invoice},admin:tenant:acme');
Every check must pass:
Route::patch('/invoices/{invoice}', InvoiceController::class)
->middleware('openfga.all:viewer:invoice:{invoice},member:tenant:acme');
Route placeholders such as {invoice} are resolved from Laravel route parameters. If the parameter is an Eloquent model, the middleware uses getKey().
Plain PHP Usage
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Psr7\HttpFactory;
use OpenFgaRbac\Client;
use OpenFgaRbac\Config;
$http = new GuzzleClient();
$factory = new HttpFactory();
$openfga = new Client(
new Config(
apiUrl: 'http://localhost:8080',
storeId: '01H...',
authorizationModelId: '01H...',
token: null,
),
$http,
$factory,
$factory,
);
$allowed = $openfga->check('user:123', 'viewer', 'invoice:2026-001');
Advanced OpenFGA Client
Contextual Tuples And Conditions
use OpenFgaRbac\TupleKey;
$result = $openfga->checkRaw(
user: 'user:123',
relation: 'viewer',
object: 'document:roadmap',
contextualTuples: [
TupleKey::make('user:123', 'member', 'team:finance'),
],
context: [
'ip' => '127.0.0.1',
],
consistency: 'HIGHER_CONSISTENCY',
);
Batch Checks
$batch = $openfga->batchCheck([
[
'correlation_id' => 'invoice-view',
'tuple_key' => [
'user' => 'user:123',
'relation' => 'viewer',
'object' => 'invoice:2026-001',
],
],
]);
List Objects And Users
$objects = $openfga->listObjects('user:123', 'viewer', 'invoice');
$users = $openfga->listUsers(
object: 'invoice:2026-001',
relation: 'viewer',
userFilters: [
['type' => 'user'],
],
);
Tuple Writes
use OpenFgaRbac\TupleKey;
$openfga->writeTuple('user:123', 'viewer', 'invoice:2026-001');
$openfga->deleteTuple('user:123', 'viewer', 'invoice:2026-001');
$openfga->writeAdvanced(
writes: [
TupleKey::make('user:123', 'viewer', 'invoice:2026-001'),
],
deletes: [
TupleKey::make('user:456', 'viewer', 'invoice:2026-001'),
],
onDuplicate: 'ignore',
onMissing: 'ignore',
);
Models, Assertions, Changes, And Stores
$models = $openfga->readAuthorizationModels();
$model = $openfga->readAuthorizationModel('01H...');
$authorizationModelId = $openfga->writeAuthorizationModel([
'schema_version' => '1.1',
'type_definitions' => [
['type' => 'user'],
],
]);
$openfga->writeAssertions('01H...', [
[
'tuple_key' => [
'user' => 'user:123',
'relation' => 'viewer',
'object' => 'invoice:2026-001',
],
'expectation' => true,
],
]);
$assertions = $openfga->readAssertions('01H...');
$changes = $openfga->readChanges(type: 'invoice');
$stores = $openfga->listStores();
$store = $openfga->getStore();
Available Client Methods
Low-level OpenFGA client:
checkcheckRawbatchChecklistObjectslistObjectsRawlistUsersexpandreadTupleswriteTupledeleteTuplewritedeletewriteAdvancedwriteAuthorizationModelreadAuthorizationModelreadAuthorizationModelswriteAssertionsreadAssertionsreadChangescreateStorelistStoresgetStoredeleteStore
RBAC helper methods:
createRoledeleteRolecreatePermissiondeletePermissionlistRolesgetAllRoleslistPermissionsgetAllPermissionsassignRolerevokeRolehasRoleuserRolesrolesAssignedToUserusersAssignedToRolegrantRolePermissionrevokeRolePermissionrolePermissionscancanAnycanAll
Testing
Run tests in Docker:
docker run --rm -v "$PWD:/app" -w /app composer:2 bash -lc "composer install && vendor/bin/phpunit"
Or use Composer:
composer test
Versioning
This package follows semantic versioning. Tag releases with Git tags:
git tag v0.1.0
git push origin v0.1.0
Packagist will expose tagged versions as Composer releases.
License
MIT