The evansims/openfga-php
package is an unofficial/experimental PHP SDK for OpenFGA and Okta FGA. It's fast, lightweight, and easy to use.
- OpenFGA and Okta FGA are supported
- Client Credentials flow and shared key authentication are supported
- All API endpoints are supported
- Networking is implemented using the PSR-7, PSR-17 and PSR-18 PHP-FIG interoperability standards
- PHP 8.4+
- Composer 2
- Access to an OpenFGA or Okta FGA instance
composer require evansims/openfga-php
Important
Your application must fulfill the PSR-7, PSR-17, and PSR-18 implementations. If you're unable to install the SDK due to a missing implementation, first install any libraries of your preference that implement those interfaces, and then retry. For example: composer require kriswallsmith/buzz nyholm/psr7
.
Note
If you're not using authentication, you can ignore this step.
The SDK supports two types of credentials: OIDC and shared key. OIDC ("client credentials flow") credentials are used to authenticate with an Okta FGA instance, while shared key credentials can be used to authenticate with an OpenFGA instance.
To configure the SDK with your credentials, create an appropriate Credentials
class instance for your authentication type. Later on, you'll pass this instance to the ClientConfiguration
constructor as the credentialConfiguration
parameter.
For OIDC ("Client Credentials flow") credentials:
use OpenFGA\SDK\Configuration\Credentials\ClientCredentialConfiguration;
$credential = new ClientCredentialConfiguration(
apiIssuer: $_ENV['FGA_API_TOKEN_ISSUER'] ?? null,
apiAudience: $_ENV['FGA_API_AUDIENCE'] ?? null,
clientId: $_ENV['FGA_CLIENT_ID'] ?? null,
clientSecret: $_ENV['FGA_CLIENT_SECRET'] ?? null,
);
Or, when using a shared key:
use OpenFGA\SDK\Configuration\Credentials\SharedKeyCredentialConfiguration;
$credential = new SharedKeyCredentialConfiguration(
sharedKey: $_ENV['FGA_SHARED_KEY'] ?? null,
);
Next, create a ClientConfiguration
instance. This will be used to configure the SDK client, including the base URL of the FGA instance you're connecting to, the credentials you've configured, and any other options you'd like to set. For example:
use OpenFGA\SDK\Configuration\ClientConfiguration;
$configuration = new ClientConfiguration(
apiUrl: $_ENV['FGA_API_URL'] ?? null,
storeId: $_ENV['FGA_STORE_ID'] ?? null,
authorizationModelId: $_ENV['FGA_MODEL_ID'] ?? null,
credentialConfiguration: $credential, // Use the credential instance you previously created
);
Finally, create a OpenFGA\Client
instance using the configuration you've set up:
use OpenFGA\Client;
$client = new Client(
configuration: $configuration
);
All set! You're now ready to start making requests to the OpenFGA API.
This will return a list of all stores. The method returns a ListStoresResponse
object.
$stores = $client->stores()->list();
This will create a store with the name my-store-name
. The method returns a CreateStoreResponse
object.
$response = $client->stores()->create(
name: 'my-store-name'
);
echo $response->getId();
echo $response->getName();
This will return the store with the ID store-id
. The method returns a GetStoreResponse
object.
$store = $client->store(storeId: 'store-id')->get();
echo $store->getId();
echo $store->getName();
This will delete the store with the ID store-id
. The method does not return a response, but will throw an exception if the request fails.
$client->store(storeId: 'store-id')->delete();
This will return a list of all authorization models for the store with the ID store-id
.
$store = $client->store(storeId: 'store-id');
$models = $store->models()->list();
This will create a new authorization model for the store with the ID store-id
:
$store = $client->store(storeId: 'store-id');
$response = $store->models()->create(
typeDefinitions: ...,
schemaVersion: ...,
conditions: ...
);
This will return the authorization model with the ID model-id
for the store with the ID store-id
.
$store = $client->store(storeId: 'store-id');
$model = $store->model(modelId: 'model-id')->get();
echo $model->getId();
$store = $client->store(storeId: 'store-id');
$tuples = $store->tuples()->changes();
foreach ($tuples as $tuple->getKey()) {
echo $tuple->getUser();
echo $tuple->getRelation();
echo $tuple->getObject();
}
$store = $client->store(storeId: 'store-id');
// Prepare a write operation object.
$op = $store->tuples()->write();
// Ex: create a relationship tuple.
$op->write(
tuple: new Tuple(
user: 'user:anne',
relation: 'writer',
object: 'document:2021-budget'
)
);
// Ex: create multiple relationship tuples.
$op->writes(
tuples: [
new Tuple(
user: 'user:anne',
relation: 'writer',
object: 'document:2021-budget'
),
new Tuple(
user: 'user:bob',
relation: 'reader',
object: 'document:2021-budget'
)
]
);
// Ex: remove a relationship tuple.
$op->delete(
tuple: new Tuple(
user: 'user:anne',
relation: 'writer',
object: 'document:2021-budget'
),
);
// Ex: remove multiple relationship tuples.
$op->deletes([
tuples: new Tuple(
user: 'user:bob',
relation: 'reader',
object: 'document:2021-budget'
)
]);
/*
Execute the operation.
This method will not return a response, but will throw an exception if the request fails.
*/
$op->execute();
The query()
method allows you to query for tuples that match a query, without following userset rewrite rules.
For example, to query for all objects
that user:bob
has a reader
relationship with for the document
type definition:
$store = $client->store(storeId: 'store-id');
$tuples = $store->tuples()->query([
new TupleKey(
user: 'user:bob',
relation: 'reader',
object: 'document:'
)
]);
foreach ($tuples as $tuple->getKey()) {
echo $tuple->getUser();
echo $tuple->getRelation();
echo $tuple->getObject();
}
Or, to query for all users
that have reader
relationship with document:2021-budget
:
$store = $client->store(storeId: 'store-id');
$tuples = $store->tuples()->query([
new TupleKey(
object: 'document:2021-budget:',
relation: 'reader'
)
]);
foreach ($tuples as $tuple->getKey()) {
echo $tuple->getUser();
echo $tuple->getRelation();
echo $tuple->getObject();
}
Or, to query for all users
that have reader
relationship with document:2021-budget
:
$store = $client->store(storeId: 'store-id');
$tuples = $store->tuples()->query([
new TupleKey(
object: 'document:2021-budget:'
)
]);
foreach ($tuples as $tuple->getKey()) {
echo $tuple->getUser();
echo $tuple->getRelation();
echo $tuple->getObject();
}
In order to check if user:anne
has a reader
relationship with document:2021-budget
:
$store = $client->store(storeId: 'store-id');
$authorized = $store->query()->check(
tuple: new TupleKey(
user: 'user:anne',
relation: 'reader',
object: 'document:2021-budget',
),
context: [
new TupleKey(
user: 'user:anne',
relation: 'member',
object: 'time_slot:office_hours',
)
]
)
Note
The Check API caches results for a short time to optimize performance. You can request higher consistency (at the expense of increase latency) using the optional optional consistency
parameter of the check()
method. This parameter supports a CONSISTENCY enum value.
TODO
TODO
TODO
TODO
TODO
TODO