Skip to main content

Testing Models

Every OpenFGA model should be tested before deployment to ensure your authorization model is correctly designed.

The .fga.yaml contains tests for OpenFGA authorization models. If you are using Visual Studio Code as your IDE, install the OpenFGA extension to enable syntax coloring and validation.

Define the model and tuples

.fga.yaml files have the following top level items:

ObjectDescription
name (optional)A descriptive name for the test file
model or model_fileAn OpenFGA model or a reference to an external model file in fga or json format
tuples or tuple_file (optional)A set of tuples or a reference to an external tuple file in json, yaml or csv format. These are considered for all tests.
testsA set of tests that verify the return values of OpenFGA API calls

The example below defines a model and tuples:

name: Model Tests # optional

# model_file: ./model.fga # you can specify an external .fga file, or include it inline
model: |
model
schema 1.1

type user

type organization
relations
define member : [user]
define admin : [user with non_expired_grant]

condition non_expired_grant(current_time: timestamp, grant_time: timestamp, grant_duration: duration) {
current_time < grant_time + grant_duration
}

# tuple_file: ./tuples.yaml # you can specify an external file, or include it inline
tuples:

# Anne is a member of the Acme organization
- user: user:anne
relation: member
object: organization:acme

# Peter has the admin role from February 2nd 2024 0AM to 1AM
- user: user:peter
relation: admin
object: organization:acme
condition:
name: non_expired_grant
context:
grant_time : "2024-02-01T00:00:00Z"
grant_duration : 1h

Write tests

Always write tests to verify that the calls your application will make return the results you expect. A good test covers scenarios that verify every relation.

Tests have the following structure:

ObjectDescription
name (optional)A descriptive name for the test, like “Organization Membership”
tuplesA set of tuples that are only considered for the test
checkA set of tests for Check calls, each with a user/object and a set of assertions
list_objectsA set of tests for ListObjects calls, each one with a user/type and a set of assertions for any number of relations
list_usersA set of tests for ListUsers calls, each one with an object and user filter and a set of assertions for the users and excluded_users for any number of relations

Write Check tests

Check tests verify the results of the check API calls to validate access requirements for a user. Each check verification has the following structure:

ObjectDescription
userThe user type and user id you are checking for access
objectThe object type and object id related to the user
contextA set of tests for contextual parameters used to evaluate conditions
assertionsA list of relation:expected-result pairs
<relation>: <true or false>The name of the relation you want to verify and the expected result

The following example adds multiple check verifications in every test:

tests:
- name: Test
check:
- user: user:anne
object: organization:acme
assertions:
member: true
admin: false

- user: user:peter
object: organization:acme
context:
current_time : "2024-02-01T00:10:00Z"
assertions:
member: false
admin: true

Write List Objects tests

A good test covers scenarios that specify every relation for every object type that your application will need to call the list-objects API for.

The following verifies the expected results using the list_objects option in OpenFGA tests:

    list_objects:
- user: user:anne
type: organization
assertions:
member:
- organization:acme
admin: []

- user: user:peter
type: organization
context:
current_time : "2024-02-01T00:10:00Z"

assertions:
member: []
admin:
- organization:acme

The example above checks that user:anne has access to the organization:acme as a member and is not an admin of any organization. It also checks that user:peter, given the current time is February 1st 2024, 0:10 AM, is not related to any organization as a member, but is related to organization:acme as an admin.

Write List Users tests

Warning

ListUsers is currently in an experimental release. Read the announcement for more information.

List users tests verify the results of the list-users API to validate the users who or do not have access to an object

Each list users verification has the following structure:

ObjectDescription
objectThe object to list users for
user_filterSpecifies the type or userset to filter with, this must only contain one entry
user_filter.typeThe specific type of results to return with response
user_filter.relationThe specific relation of results to return with response. Specify to return usersets (optional)
contextA set of tests for contextual parameters used to evaluate conditions
assertionsA list of assertions to make
<relation>The name of the relation you want to verify
<relation>.usersThe users who should have the stated relation to the object
<relation>.excluded_usersThe users who should have explicitly not have access to the object due to evaluations of type bound public access and negation (e.g. "all users except anne")

In order to simplify test writing, the following syntax is supported for the various object types included in users and excluded_users from the API response:

  • <type>:<id> to represent a userset that is a user
  • <type>:<id>#<relation> to represent a userset that is a relation on a type
  • <type>:* to represent a userset that is a type bound public access for a type

The following is an example of using the list_users option in OpenFGA tests:

    list_users:
- object: organization:acme
user_filter:
- type: user
assertions:
member:
users:
- user:anne
excluded_users: []
admin:
users: []
excluded_users: []

- object: organization:acme
user_filter:
- type: employee
context:
current_time : "2024-02-01T00:10:00Z"
assertions:
member:
users: []
excluded_users: []
admin:
users:
- employee:peter
excluded_users: []

The example above checks that user:anne has access to the organization:acme as a member and is not an admin of any organization. It also checks that employee:peter, given the current time is February 1st 2024, 0:10 AM, is not related to any organization as a member, but is related to organization:acme as an admin.

Running tests

Tests are run using the model test CLI command. For instructions on installing the OpenFGA CLI, visit the OpenFGA CLI Github repository.

fga model test --tests <filename>.fga.yaml

When all tests pass, a summary with the number of tests passed is displayed. When a test fails, a line for every test is displayed.

$ fga model test --tests docs.fga.yaml
(PASSING) Test: Checks (4/4 passing) | ListObjects (4/4 passing)

$ fga model test --tests docs.fga.yaml
(FAILING) Test: Checks (4/4 passing) | ListObjects (3/4 passing)
✓ ListObjects(user=user:anne,relation=member,type=organization, context=<nil>)
✓ ListObjects(user=user:anne,relation=admin,type=organization, context=<nil>)
✓ ListObjects(user=user:peter,relation=member,type=organization, context=&map[current_time:2024-02-01T00:10:00Z])
ⅹ ListObjects(user=user:peter,relation=admin,type=organization, context=&map[current_time:2024-02-01T00:10:00Z]): expected=[organization:acm], got=[organization:acme], error=<nil>

Running tests using GitHub Actions

Use the OpenFGA Model Testing Action to run tests from CI/CD flows in GitHub.

Set the path to the .fga.yaml file as the store-file-path parameter when configuring the action:

name: Test Action

on:
workflow_dispatch:
pull_request:
branches:
- main

jobs:
test:
name: Run test
runs-on: ubuntu-latest
steps:
- name: Checkout Project
uses: actions/checkout@v4
- name: Run Test
uses: openfga/action-openfga-[email protected]
with:
store-file-path: ./example/model.fga.yaml

Use the FGA CLI

Learn how to use the FGA CLI.

Super Admin Example

Define a model and tests for modeling a super-admin role.

Banking Example

Define a model and tests for banking application.

Entitlements Example

Define a model and tests for B2B application entitlements.