A cross-platform CLI to interact with an OpenFGA server
- About OpenFGA
- Resources
- Installation
- Building from Source
- Usage
- Contributing
- License
OpenFGA is an open source Fine-Grained Authorization solution inspired by Google's Zanzibar paper. It was created by the FGA team at Auth0 based on Auth0 Fine-Grained Authorization (FGA), available under a permissive license (Apache-2) and welcomes community contributions.
OpenFGA is designed to make it easy for application builders to model their permission layer, and to add and integrate fine-grained authorization into their applications. OpenFGA’s design is optimized for reliability and low latency at a high scale.
- OpenFGA Documentation
- OpenFGA API Documentation
- OpenFGA Discord Community
- Zanzibar Academy
- Google's Zanzibar Paper (2019)
brew install openfga/tap/fgaDownload the .deb, .rpm or .apk packages from the releases page.
Debian:
sudo apt install ./fga_<version>_linux_<arch>.debFedora:
sudo dnf install ./fga_<version>_linux_<arch>.rpmAlpine Linux:
sudo apk add --allow-untrusted ./fga_<version>_linux_<arch>.apkdocker pull openfga/cli; docker run -it openfga/clinote that the command will be named
cli
go install github.com/openfga/cli@latestDownload the pre-compiled binaries from the releases page.
Make sure you have Go 1.20 or later installed. See the Go downloads page.
-
Clone the repo to a local directory, and navigate to that directory:
git clone https://github.com/openfga/cli.git && cd cli
-
Then use the build command:
go build -o ./dist/fga main.go
or if you have
makeinstalled, just run:make build
-
Run the OpenFGA CLI with:
./dist/fga
For any command that interacts with an OpenFGA server, these configuration values can be passed (where applicable)
| Name | Flag | CLI |
|---|---|---|
| Server Url | --server-url |
FGA_SERVER_URL |
| Shared Secret | --api-token |
FGA_API_TOKEN |
| Client ID | --client-id |
FGA_CLIENT_ID |
| Client Secret | --client-secret |
FGA_CLIENT_SECRET |
| Token Issuer | --api-token-issuer |
FGA_API_TOKEN_ISSUER |
| Token Audience | --api-audience |
FGA_API_AUDIENCE |
| Store ID | --store-id |
FGA_STORE_ID |
| Authorization Model ID | --model-id |
FGA_MODEL_ID |
| Description | command | parameters | example |
|---|---|---|---|
| Create a Store | create |
--name |
fga store create --name="FGA Demo Store" |
| List Stores | list |
fga store list |
|
| Get a Store | get |
--store-id |
fga store get --store-id=01H0H015178Y2V4CX10C2KGHF4 |
| Delete a Store | delete |
--store-id |
fga store delete --store-id=01H0H015178Y2V4CX10C2KGHF4 |
fga store create
--name: Specifies the name of the store to be created
fga store create --name "FGA Demo Store"
{
"id": "01H0H015178Y2V4CX10C2KGHF4",
"name": "FGA Demo Store",
"created_at": "2023-05-19T16:10:07.637585677Z",
"updated_at": "2023-05-19T16:10:07.637585677Z"
}fga store list
--max-pages: Max number of pages to retrieve (default: 20)
fga store list
{
"stores": [{
"id": "..",
"name": "..",
"created_at": "",
"updated_at": "",
"deleted_at": ""
}, { .. }]
}fga store get
--store-id: Specifies the store id to get
fga store get --store-id=01H0H015178Y2V4CX10C2KGHF4
{
"id": "01H0H015178Y2V4CX10C2KGHF4",
"name": "FGA Demo Store",
"created_at": "2023-05-19T16:10:07.637585677Z",
"updated_at": "2023-05-19T16:10:07.637585677Z"
}fga store delete
--store-id: Specifies the store id to delete
fga store delete --store-id=01H0H015178Y2V4CX10C2KGHF4
{}model
| Description | command | parameters | example |
|---|---|---|---|
| Read Authorization Models | list |
--store-id |
fga model list --store-id=01H0H015178Y2V4CX10C2KGHF4 |
| Write Authorization Model | write |
--store-id, --file |
fga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 --file=model.json |
| Read a Single Authorization Model | get |
--store-id, --model-id |
fga model get --store-id=01H0H015178Y2V4CX10C2KGHF4 --model-id=01GXSA8YR785C4FYS3C0RTG7B1 |
fga model list
--store-id: Specifies the store id--max-pages: Max number of pages to retrieve (default: 20)
fga model list --store-id=01H0H015178Y2V4CX10C2KGHF4
[{
"schema_version": "1.1",
"id": "01GXSA8YR785C4FYS3C0RTG7B1",
"type_definitions": [
{"type": "user"},
// { ... }
],
},
// { ... }
]fga model write
--store-id: Specifies the store id--file: Specifies the file containing the model in JSON format
fga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 --file=model.jsonfga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 '{"type_definitions": [ { "type": "user" }, { "type": "document", "relations": { "can_view": { "this": {} } }, "metadata": { "relations": { "can_view": { "directly_related_user_types": [ { "type": "user" } ] }}}} ], "schema_version": "1.1"}'
{
"authorization_model_id":"01GXSA8YR785C4FYS3C0RTG7B1"
}fga model get
--store-id: Specifies the store id--model-id: Specifies the model id
fga model get --store-id=01H0H015178Y2V4CX10C2KGHF4 --model-id=01GXSA8YR785C4FYS3C0RTG7B1
{
"schema_version": "1.1",
"id": "01GXSA8YR785C4FYS3C0RTG7B1",
"type_definitions": [
{"type": "user"},
// { ... }
],
}If model-id is not specified when using the get command, the latest authorization model will be returned.
fga model get
--store-id: Specifies the store id
fga model get --store-id=01H0H015178Y2V4CX10C2KGHF4
{
"schema_version": "1.1",
"id": "01GXSA8YR785C4FYS3C0RTG7B1",
"type_definitions": [
{"type": "user"},
// { ... }
],
}fga model validate
fga model validate '{"schema_version":"1.1,"type_definitions":[{"type":"user"}]}'
- Valid model with an ID
{"id":"01GPGWB8R33HWXS3KK6YG4ETGH","created_at":"2023-01-11T16:59:22Z","is_valid":true}- Valid model without an ID
{"is_valid":true}- Invalid model with an ID
{"id":"01GPGTVEH5NYTQ19RYFQKE0Q4Z","created_at":"2023-01-11T16:33:15Z","is_valid":false,"error":"invalid schema version"}- Invalid model without an ID
{"is_valid":false,"error":"the relation type 'employee' on 'member' in object type 'group' is not valid"}tuple
| Description | command | parameters | example |
|---|---|---|---|
| Write Relationship Tuples | write |
--store-id, --model-id |
fga tuple write --store-id=01H0H015178Y2V4CX10C2KGHF4 '{"schema_version":"1.1","type_definitions":[...]}' |
| Delete Relationship Tuples | delete |
--store-id, --model-id |
fga tuple delete --store-id=01H0H015178Y2V4CX10C2KGHF4 |
| Read Relationship Tuples | read |
--store-id, --model-id |
fga tuple read --store-id=01H0H015178Y2V4CX10C2KGHF4 --model-id=01GXSA8YR785C4FYS3C0RTG7B1 |
| Read Relationship Tuple Changes (Watch) | changes |
--store-id, --model-id |
fga tuple changes --store-id=01H0H015178Y2V4CX10C2KGHF4 --model-id=01GXSA8YR785C4FYS3C0RTG7B1 |
| Import Relationship Tuples | import |
--store-id, --model-id, --file |
fga tuple import --store-id=01H0H015178Y2V4CX10C2KGHF4 --model-id=01GXSA8YR785C4FYS3C0RTG7B1 --file=tuples.json |
fga tuple write --store-id=
<user>: User<relation>: Relation<object>: Object--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)
fga tuple write --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document:roadmap
{}fga tuple delete --store-id=
<user>: User<relation>: Relation<object>: Object--store-id: Specifies the store id
fga tuple delete --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document:roadmap
{}fga tuple read [--user=] [--relation=] [--object=] --store-id=
--store-id: Specifies the store id--user: User--relation: Relation--object: Object
fga tuple read --store-id=01H0H015178Y2V4CX10C2KGHF4 --user user:anne --relation can_view --object document:roadmap
{
"tuples": [
{
"key": {
"object": "document:roadmap",
"relation": "can_view",
"user": "user:anne"
},
"timestamp": "2023-07-06T15:12:55.080666875Z"
}
]
}fga tuple changes --type --store-id=
--store-id: Specifies the store id--type: restrict to a specific type (optional)--max-pages: Max number of pages to retrieve (default: 20)
fga tuple changes --store-id=01H0H015178Y2V4CX10C2KGHF4 --type document
{
"changes": [
{
"operation": "TUPLE_OPERATION_WRITE",
"timestamp": "2023-07-06T15:12:40.294950382Z",
"tuple_key": {
"object": "document:roadmap",
"relation": "can_view",
"user": "user:anne"
}
}
]
}fga tuple import --store-id= [--model-id=] --file= [--max-tuples-per-write=] [--max-parallel-requests=]
--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)--file: Specifies the file name,yamlandjsonfiles are supported--max-tuples-per-write: Max tuples to send in a single write (optional, default=20)--max-parallel-requests: Max requests to send in parallel (optional, default=4)
File format should be: In YAML:
- user: user:anne
relation: can_view
object: document:roadmap
- user: user:beth
relation: can_view
object: document:roadmapIn JSON:
[{
"user": "user:anne",
"relation": "can_view",
"object": "document:roadmap"
}, {
"user": "user:beth",
"relation": "can_view",
"object": "document:roadmap"
}]fga tuple import --store-id=01H0H015178Y2V4CX10C2KGHF4 --file tuples.json
{
"successful": [
{
"object":"document:roadmap",
"relation":"writer",
"user":"user:annie"
}
],
"failed": [
{
"tuple_key": {
"object":"document:roadmap",
"relation":"writer",
"user":"carl"
},
"reason":"Write validation error ..."
}
]
}query
| Description | command | parameters | example |
|---|---|---|---|
| Check | check |
--store-id, --model-id |
fga query check --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document:roadmap |
| List Objects | list-objects |
--store-id, --model-id |
fga query list-objects --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document |
| List Relations | list-relations |
--store-id, --model-id |
fga query list-relations --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne document |
| Expand | expand |
--store-id, --model-id |
fga query expand --store-id=01H0H015178Y2V4CX10C2KGHF4 can_view document:roadmap |
fga query check [--contextual-tuple " "]* --store-id= [--model-id=]
--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)--contextual-tuple: Contextual tuples
fga query check --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document:roadmap --contextual-tuple "user:anne can_view folder:product" --contextual-tuple "folder:product parent document:roadmap"
{
"allowed": true,
}fga query list-objects <object_type> [--contextual-tuple " "]* --store-id= [--model-id=]
--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)--contextual-tuple: Contextual tuples (optional) (can be multiple)
fga query list-objects --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne can_view document --contextual-tuple "user:anne can_view folder:product" --contextual-tuple "folder:product parent document:roadmap"
{
"objects": [
"document:roadmap",
"document:budget"
],
}fga query list-objects [--relation ]* [--contextual-tuple " "]* --store-id= [--model-id=]
--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)--contextual-tuple: Contextual tuples (optional) (can be multiple)
fga query list-relations --store-id=01H0H015178Y2V4CX10C2KGHF4 user:anne document:roadmap --relation can_view
{
"relations": [
"can_view"
],
}fga query expand --store-id= [--model-id=]
--store-id: Specifies the store id--model-id: Specifies the model id to target (optional)
fga query expand --store-id=01H0H015178Y2V4CX10C2KGHF4 can_view document:roadmap
{
"tree": {
"root": {
"name": "repo:openfga/openfga#reader",
"union": {
"nodes": [{
"leaf": {
"users": {
"users": ["user:anne"]
}
},
"name": "repo:openfga/openfga#reader"
}]
}
}
}
}See CONTRIBUTING.
This project is licensed under the Apache-2.0 license. See the LICENSE file for more info.