mvonline / openfga-laravel-rbac
PHP and Laravel SDK for using OpenFGA as an RBAC authorization operator.
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.8
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0
Requires (Dev)
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
- illuminate/support: Required for Laravel service provider auto-discovery.
README
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