Code Monkey home page Code Monkey logo

community's Introduction

OpenFGA

Go Reference GitHub release (latest SemVer) Docker Pulls Codecov Go Report CII Best Practices Join our community Twitter FOSSA Status Artifact HUB OpenSSF Scorecard SLSA 3

A high-performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar.

OpenFGA is designed to make it easy for developers to model their application permissions and add and integrate fine-grained authorization into their applications.

It allows in-memory data storage for quick development, as well as pluggable database modules. It currently supports PostgreSQL 14 and MySQL 8.

It offers an HTTP API and a gRPC API. It has SDKs for Java, Node.js/JavaScript, GoLang, Python and .NET. Look in our Community section for third-party SDKs and tools. It can also be used as a library (see example).

Getting Started

The following section aims to help you get started quickly. Please look at our official documentation for in-depth information.

Setup and Installation

โ„น๏ธ The following sections setup an OpenFGA server using the default configuration values. These are for rapid development and not for a production environment. Data written to an OpenFGA instance using the default configuration with the memory storage engine will not persist after the service is stopped.

For more information on how to configure the OpenFGA server, please take a look at our official documentation on Running in Production.

Docker

OpenFGA is available on Dockerhub, so you can quickly start it using the in-memory datastore by running the following commands:

docker pull openfga/openfga
docker run -p 8080:8080 -p 3000:3000 openfga/openfga run

Tip

The OPENFGA_HTTP_ADDR environment variable can used to configure the address at which the playground expects the OpenFGA server to be. For example, docker run -e OPENFGA_PLAYGROUND_ENABLED=true -e OPENFGA_HTTP_ADDR=0.0.0.0:4000 -p 4000:4000 -p 3000:3000 openfga/openfga run will start the OpenFGA server on port 4000, and configure the playground too.

Docker Compose

docker-compose.yaml provides an example of how to launch OpenFGA with Postgres using docker compose.

  1. First, either clone this repo or curl the docker-compose.yaml file with the following command:

    curl -LO https://openfga.dev/docker-compose.yaml
  2. Then, run the following command:

    docker compose up

Package Managers

If you are a Homebrew user, you can install OpenFGA with the following command:

brew install openfga

Pre-compiled Binaries

Download your platform's latest release and extract it. Then run the binary with the command:

./openfga run

Building from Source

There are two recommended options for building OpenFGA from source code:

Building from source with go install

Make sure you have Go 1.20 or later installed. See the Go downloads page.

You can install from source using Go modules:

  1. First, make sure $GOBIN is on your shell $PATH:

    export PATH=$PATH:$(go env GOBIN)
  2. Then use the install command:

    go install github.com/openfga/openfga/cmd/openfga
  3. Run the server with:

    ./openfga run

Building from source with go build

Alternatively you can build OpenFGA by cloning the project from this Github repo, and then building it with the go build command:

  1. Clone the repo to a local directory, and navigate to that directory:

    git clone https://github.com/openfga/openfga.git && cd openfga
  2. Then use the build command:

    go build -o ./openfga ./cmd/openfga
  3. Run the server with:

    ./openfga run

Verifying the Installation

Now that you have Set up and Installed OpenFGA, you can test your installation by creating an OpenFGA Store.

curl -X POST 'localhost:8080/stores' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "openfga-demo"
}'

If everything is running correctly, you should get a response with information about the newly created store, for example:

{
  "id": "01G3EMTKQRKJ93PFVDA1SJHWD2",
  "name": "openfga-demo",
  "created_at": "2022-05-19T17:11:12.888680Z",
  "updated_at": "2022-05-19T17:11:12.888680Z"
}

Playground

The Playground facilitates rapid development by allowing you to visualize and model your application's authorization model(s) and manage relationship tuples with a locally running OpenFGA instance.

To run OpenFGA with the Playground disabled, provide the --playground-enabled=false flag.

./openfga run --playground-enabled=false

Once OpenFGA is running, by default, the Playground can be accessed at http://localhost:3000/playground.

In the event that a port other than the default port is required, the --playground-port flag can be set to change it. For example,

./openfga run --playground-enabled --playground-port 3001

Profiler (pprof)

Profiling through pprof can be enabled on the OpenFGA server by providing the --profiler-enabled flag.

./openfga run --profiler-enabled

This will start serving profiling data on port 3001. You can see that data by visiting http://localhost:3001/debug/pprof.

If you need to serve the profiler on a different address, you can do so by specifying the --profiler-addr flag. For example,

./openfga run --profiler-enabled --profiler-addr :3002

Once the OpenFGA server is running, in another window you can run the following command to generate a compressed CPU profile:

go tool pprof -proto -seconds 60 http://localhost:3001/debug/pprof/profile
# will collect data for 60 seconds and generate a file like pprof.samples.cpu.001.pb.gz

That file can be analyzed visually by running the following command and then visiting http://localhost:8084:

go tool pprof -http=localhost:8084 pprof.samples.cpu.001.pb.gz

Next Steps

Take a look at examples of how to:

Don't hesitate to browse the official Documentation, API Reference.

Limitations

MySQL Storage engine

The MySQL storage engine has a lower length limit for some properties of a tuple compared with other storage backends. For more information see the docs.

OpenFGA's MySQL Storage Adapter was contributed to OpenFGA by @twintag. Thanks!

Production Readiness

The core OpenFGA service has been in use by Okta FGA in production since December 2021.

OpenFGA's Memory Storage Adapter was built for development purposes only and is not recommended for a production environment, because it is not designed for scalable queries and has no support for persistence.

You can learn about more organizations using OpenFGA in production here. If your organization is using OpenFGA in production please consider adding it to the list.

The OpenFGA team will do its best to address all production issues with high priority.

Contributing

See CONTRIBUTING.

Community Meetings

We hold a monthly meeting to interact with the community, collaborate and receive/provide feedback. You can find more details, including the time, our agenda, and the meeting minutes here.

community's People

Contributors

aaguiarz avatar andreadistefano avatar booniepepper avatar dada-engineer avatar donch1989 avatar ghstahl avatar golanglemonade avatar igboyes avatar jaormx avatar jcaracoche-eiwa avatar jmiettinen avatar jon-whit avatar massigori avatar matthewpereira avatar midaslamb avatar nikosft avatar nkreiger avatar ntotten avatar oasisk avatar paulinejamin avatar paulosuzart avatar powersa avatar rhamzeh avatar richardakman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

community's Issues

Is it possible to read for multiple tuple keys at a time?

๐Ÿ‘‹ I would like to know if there is a way to read several tuple_keys in a single READ query.

Imagine the following scenario:
I have 4 objects: a, b, c, d which exist in a folder structure.

When the folder is deleted, I want to delete the tuples associated with object a, b, c, and d.

Right now when this happens, I have to do 4 separate READ requests like this:

{
   "tuple_key": {
       {
           "object": "a"
       }
   }
}
{
   "tuple_key": {
       {
           "object": "b"
       }
   }
}

etc.

Once I receive all these tuples back (after making at least 4 network requests), only then can I start issuing the delete requests for all of them.

If the folder has thousands of pages, then this will not scale well at all.

Is there a way to include tuple_keys as an array to pass in multiple objects at the same time?

Automatic Relationship Expiration

It would be really cool to be able to create relationships that automatically expire after a certain period of time. For temporary access in a distributed system

How to model indirect relationship that depend on an attribute?

Hi,

Thanks for the great work on OpenFGA!

I'm evaluating adopting it and there is one particular use case that I can figure out: How to model indirect relationships that depend on an attribute?

Let's use the Google Drive example: you have users, folders and documents.
By default, when you have access to a folder, you have access to all the folders inside it.
I want to have a setting at folder level to enable visibility of subfolders, i.e.
Folder A is inside folder B and folder B has "subfolder visibility" set to true.
User X has access to Folder B. Thus, user X has access to folder A.
Folder B "subfolder visibility" set to false.
User X has access to folder B contents but it has no access to folder A contents.

Could this be modelled with the current version of OpenFGA?

Allow API to crawl data without IDs

Hi there,

Recently, we had an ubiquitous language update which forced us to make our authorization model evolve. Nothing difficult so far. But this also forces us to migrate our data, changing from one type to another. Unfortunately, the API does not allow to crawl data without providing IDs.

The idea here is to be able to call the read enpoint (/stores/{store_id}/read) without providing IDs (we would still be able to provide both page_size and continuation_token if required).

Here's an example of such a call:

{
 "tuple_key": {
     "user": "user:",
     "relation": "reader",
     "object": "document:"
  }
}

The fact that we do not provide a user ID nor a document one would mean we want to look for ALL relations involving users having a reader relation with any document.

The response would still be the same format:

{
  "tuples": [
    {
      "key": {
        "user": "user:john",
        "relation": "reader",
        "object": "document:2021-budget"
      },
      "timestamp": "2021-10-06T15:32:11.128Z"
    },
    {
      "key": {
        "user": "user:john",
        "relation": "reader",
        "object": "document:2022-budget"
      },
      "timestamp": "2021-10-06T15:32:11.128Z"
    },
    {
      "key": {
        "user": "user:jane",
        "relation": "reader",
        "object": "document:2022-budget"
      },
      "timestamp": "2021-10-06T15:32:11.128Z"
    },
    {
      "key": {
        "user": "user:jane",
        "relation": "reader",
        "object": "document:2023-budget"
      },
      "timestamp": "2021-10-06T15:32:11.128Z"
    }
  ],
  "continuation_token": "eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ=="
}

The response above shows that we have 2 users (John and Jane) having relations with 3 documents 2021-budget, 2022-budget and 2023-budget. I don't have any opinion on how data should ordered before being returned, the current logic can remain the same.

I am aware that this may have an impact on OpenFga performances, but without such a behavior, we would not be able to update our data without directly querying the database (which is definitely something we do not want to do).

Please let me know if you need further information, cheers!

Support for Google Spanner as an additional database in OpenFGA

Checklist

Describe the problem you'd like to have solved

Currently OpenFGA supports only PostgreSQL or MySQL. However for applications that want to use some high performance databases like Google Spanner or Amazon Aurora or Azure CosmosDB can not do so. It would be really helpful if we don't have the database option constraint.

Describe the ideal solution

To add support for other databases such as,

  • Google Spanner
  • Amazon Aurora
  • Azure CosmosDB
  • MongoDB
  • etc

Alternatives and current workarounds

No response

Additional context

No response

[Feature Request] openfga version endpoint

I am not able to find an endpoint (or other way) to determining what openfga version we are running. If something like this doesn't already exist I would like to request that we add the version (Currently: v0.3.7) to the healthz endpoint or an additional endpoint. This would allow us to confirm what version we are running and also use that version for future use.

Healthcheck:
curl -X GET localhost/healthz

Make the Playground able to convert from JSON to DSL

Hi everyone!

This is more like a feature request instead of an issue. I am assuming the Playground utilizes the syntax-transformer under the hood to allow the transformation from DSL to JSON. It would be great to have the opposite as well, as we could choose to store either the DSL or the JSON file.

I also understand that the Playground isn't open source, is there any plan for it to be?

Cheers,,

Bruno

Enterprise support for OpenFGA in production

Hi Auth0 Team, is there any enterprise support model available for OpenFGA ? I have been following Auth0 - FGA SaaS since quite sometime, it seems OpenFGA has most of its feature other than UI. FGA-SaaS is available only under developer preview mode, while OpenFGA can be hosted on-prem and used in production by any enterprise. I am very much interested to know if there is any support model available for OpenFGA from Auth0 team.

Do not clear tuples in playground when there are problems with request

ๅฝ“ไฝฟ็”จPlaygroundไฟๅญ˜Tuplesๆ—ถ๏ผŒๅฆ‚ๆžœๆŠฅ้”™ไบ†๏ผŒ่กจๅ•ๅŸŸ้‡Œ็š„ๅ†…ๅฎนไผš่ขซๆธ…็ฉบใ€‚

ๅธŒๆœ›่ฟ™ๆ—ถๅ€™ไธไผšๆธ…็ฉบ่กจๅ•ๅŸŸ็š„ๅ†…ๅฎน๏ผŒไปฅไพฟๆ›ดๅฟซๆท็š„ๆ›ดๆ”นๅ†…ๅฎน้‡ๆ–ฐๆไบคใ€‚

Get all tuples related to a user without specifying relation or object

Checklist

  • I have looked into the README and have not found a suitable solution or answer.
  • I have looked into the documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have upgraded to the latest version of OpenFGA and the issue still persists.
  • I have searched the Discord community and have not found a suitable solution or answer.
  • I agree to the terms within the OpenFGA Code of Conduct.

Description

Our model allows custom role creation & assigning permissions to this role on pre-defined resources, the permissions are get , list , create , update & delete.

Our model is as described in Store data.

We would like to fetch all permissions that role:role1 has, read or list objects API cant help us fetch us because of mandatory request attributes each of API's have

Expectation

We would like to fetch all permission tuples for role:role1

Reproduction

model specified above

Store data

model_file: |
 model
  schema 1.1

type user

type org
  relations
    define viewer: [user]
    define editor: [user]

type folder
  relations
    define GET: [user, role#assignee] or viewer from owningOrg
    define POST: [user, role#assignee] or editor from owningOrg
    define owningOrg: [org]


type dashboard
  relations
    define GET: [user, role#assignee] or viewer from owningOrg
    define POST: [user, role#assignee] or editor from owningOrg
    define owningOrg: [org]

type function
  relations
    define GET: [user, role#assignee] or viewer from owningOrg
    define POST: [user, role#assignee] or editor from owningOrg
    define owningOrg: [org]

type role
  relations
    define assignee: [user] 
    define viewer: [user]

tuples:
  - user: [email protected]
    relation: assignee
    object: role:role1
  - user: role:role1#assignee
    relation: POST
    object: function:a

OpenFGA version

v1.4.0

How are you running OpenFGA?

In Docker

What datastore are you using?

Postgres

OpenFGA Flags

NA

Logs

No response

Ability to read DB secrets from Vault

Problem:

At the moment, the database URL/password has to be passed through flags or env variables. This is a limiting factor to the architectures that depend on Vault storing the DB creds, Vault rotating the DB creds periodically.

Are there any plans to provide Vault support?

Show visualization for the relationship between different Types Definitions across Types

Checklist

Describe the problem you'd like to have solved

Right now it is difficult to visualize how a specific Type Definition is compose of direct and implied relationships.

Describe the ideal solution

Ideally there would be some way to visual the implied relationship / the complete relationship hierarchy for a given Type Definitions.

The example would be the Repo:Admin -> Org:Repo Admin
Screenshot 2024-04-15 at 9 10 40โ€ฏAM

I don't think just showing all relationships N-degrees away makes sense since it would be chaotic. When you hover a Type, then show the Types full definition with direct and implied relationships

Alternatives and current workarounds

Currently, I don't think there is any easy way way to see the implied relationships. You have to to read the model and assertions and reason about it / draw it out.

Additional context

As a model gets more complex, it is hard to reason about the implied relationships. Having visualizations for implied definitions would definitely help being simplicity back

[Use-Case Question] How to implement negate condition ?

Hello,

I'm working with a system where a user is granted to groups of objects following 2 principles:

  1. The user is allowed to access some groups (inclusion).
  2. The user is not allowed to access some groups so, he/she has access to all other groups (exclusion).

As example, let's say the user bob is granted to groups A and B (among thousands of groups).
So, bobis supposed to see all objecta that are link to groups A and B. No issue with that.

But, the user alice must not have access to groups B and C. That means she has access to all other groups.

I've tried to define the model like

model
  schema 1.1

type user

type group
  relations
    define allowed: [user]
    define denied: [user]
    define is_granted: allowed but not denied

where:

  • user:bob is allowed to group:A
  • user:bob is allowed to group:B
  • user:alice is denied to group:B
  • user:alice is denied to group:C
    Also, as the allowed and denied relations are mutually exclusive, a user can't have both set. Either a group is allowed or denied.

Some expected results are:

  • is user:bob related to group:A as is_granted? -> YES
  • is user:bob related to group:B as is_granted? -> YES
  • is user:bob related to group:C as is_granted? -> NO
  • is user:bob related to group:Z as is_granted? -> NO
  • is user:alice related to group:A as is_granted? -> YES (because group A is not explicitly denied)
  • is user:alice related to group:B as is_granted? -> NO (because group B is explicitly denied)
  • is user:alice related to group:C as is_granted? -> NO (because group C is explicitly denied)
  • is user:alice related to group:Z as is_granted? -> YES (because group Z is not explicitly denied)

But the is_granted relation is not exactly the one I need because the exclusion operator but not is not correct.
I need something like define is_granted: allowed or not denied that

Do you think there is another way to implement such case ?

Many thanks,
Stephane

Feature Request: Playground should have export and import of a model, tuples and assertions

It is easy enough to copy the authorization model, but I can't copy the tuples or assertions.

It would be nice to export the entire store, within reason, when modeling. i.e. put a limit on the number or tuples and assertions allowed.

This would let me import it into a developer docker instance of openFGA

The import should also be exposed as an api so I can seed openFGA easily for unit tests and development.

Also, it would be nice to in line edit tuples and assertions.
Right now, its delete and replace.

Is it possible to add tuples with contextual tuples?

Hello, I have a scenario like this. We sell plans to businesses and they include features. Features contain resources. Resources are the endpoints of our webapi services.

Users become members of businesses.
A user can register for more than one business. (contextual)

However, if the business administrator wants to block a user from accessing the relevant resource, they cannot do so.

This is my scheme.

type user
type plan
  relations
    define subscriber as self
    define subscriber_member as member from subscriber
type business
  relations
    define member as self and user_in_context
    define user_in_context as self
type feature
  relations
    define associated_plan as self
    define feature_member as subscriber_member from associated_plan
type resource
  relations
    define associated_feature as self
    define can_access as feature_member from associated_feature but not blocked
    define blocked as self

I added a relation named blocked in the Resources type and if I can define the user with this relation a relation tuple like below will solve all my problem.

{
  "tuple_key": {
    "user": "user:john",
    "relation": "blocked",
    "object": "resource:getreceipt"
  },
  "contextual_tuples": {
    "tuple_keys": [
      {
        "user": "user:john",
        "relation": "user_in_context",
        "object": "business:example"
      }
    ]
  }
}

When a user is blocked access to resources, all businesses are blocked from their resources. I want to block access to resources only in the context of the business.

Make authorization model endpoints HATEOAS / HAL compliant

Nowadays, we can retrieve all authorization models by calling the endpoint /stores/{store_id}/authorization-models, which allows us to specify how many items we want per page using the query parameter page_size. Unfortunatly, only a continuation_token is retrieved, which can not indicate how many authorization models can still be retrieved, forcing us to call the same endpoint again and again until recieving less ahtorization models than specified in the query or checking if a token has been provided.

A successful solution would be to use HATEOAS HAL specification.

With that, the endpoint could retrieve authorization models with pagination links calculated on the fly depending on how many models are currently stored in the database, but also links related to the model itself within the object. Here is an example when calling /stores/{store_id}/authorization_models with page_size=1 and page_index=2:

{
   "items":[
      {
         "id":"{authorization_model_id}",
         "_links":{
            "self":{
               "href":"/stores/{store_id}/authorization-models/{authorization_model_id}",
               "method":"GET"
            }
         }
      }
   ],
   "total":5,
   "_links":{
      "self":{
         "href":"/stores/{store_id}/authorization-models?page_size=1&page_index=2",
         "method":"GET"
      },
      "first":{
         "href":"/stores/{store_id}/authorization-models?page_size=1&page_index=1",
         "method":"GET"
      },
      "prev":{
         "href":"/stores/{store_id}/authorization-models?page_size=1&page_index=1",
         "method":"GET"
      },
      "next":{
         "href":"/stores/{store_id}/authorization-models?page_size=1&page_index=3",
         "method":"GET"
      },
      "last":{
         "href":"/stores/{store_id}/authorization-models?page_size=1&page_index=5",
         "method":"GET"
      },
      "create":{
         "href":"/stores/{store_id}/authorization-models",
         "method":"POST"
      }
   }
}

In the example above, the links self, first, last and create are permanent, while prev and next are optional, depending on the current page index and authorization models count. With that, it would be much easier for an API consumer to navigate thouth all available authorization models, as everything would be provided by the API itself.

As usual, let me know if further information are required. Cheers!

ListObjects fails to retrieve all items

Although assert validates a read user from AdminTeam that it has read right to a certain resource,
the ListObjects method does not return all items that it actually has read access, and some times it returns different results on back to back calls.

Authorization Model (Schema v1.1)

DSL

model
  schema 1.1
type user
type organization
  relations
    define admin_team: [super_team]
    define has_delete: owner_user or has_delete from admin_team
    define has_read: has_write or read_user or has_read from admin_team
    define has_write: owner_user or write_user or has_write from admin_team
    define owner_user: [user]
    define read_user: [user]
    define write_user: [user]
type organization_resource
  relations
    define has_delete: has_delete from parent_org
    define has_read: has_write or has_read from parent_org
    define has_write: has_write from parent_org
    define parent_org: [organization]
type super_team
  relations
    define has_delete: manager_user
    define has_read: has_write or read_user
    define has_write: manager_user or write_user
    define manager_user: [user]
    define read_user: [user]
    define write_user: [user]

JSON:

{
  "schema_version": "1.1",
  "type_definitions": [{
    "type": "organization",
    "relations": {
      "admin_team": {
        "this": {}
      },
      "has_delete": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "owner_user"
            }
          }, {
            "tupleToUserset": {
              "tupleset": {
                "object": "",
                "relation": "admin_team"
              },
              "computedUserset": {
                "object": "",
                "relation": "has_delete"
              }
            }
          }]
        }
      },
      "has_read": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "has_write"
            }
          }, {
            "computedUserset": {
              "object": "",
              "relation": "read_user"
            }
          }, {
            "tupleToUserset": {
              "tupleset": {
                "object": "",
                "relation": "admin_team"
              },
              "computedUserset": {
                "object": "",
                "relation": "has_read"
              }
            }
          }]
        }
      },
      "has_write": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "owner_user"
            }
          }, {
            "computedUserset": {
              "object": "",
              "relation": "write_user"
            }
          }, {
            "tupleToUserset": {
              "tupleset": {
                "object": "",
                "relation": "admin_team"
              },
              "computedUserset": {
                "object": "",
                "relation": "has_write"
              }
            }
          }]
        }
      },
      "owner_user": {
        "this": {}
      },
      "read_user": {
        "this": {}
      },
      "write_user": {
        "this": {}
      }
    },
    "metadata": {
      "relations": {
        "admin_team": {
          "directly_related_user_types": [{
            "type": "super_team"
          }]
        },
        "has_delete": {
          "directly_related_user_types": []
        },
        "has_read": {
          "directly_related_user_types": []
        },
        "has_write": {
          "directly_related_user_types": []
        },
        "owner_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        },
        "read_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        },
        "write_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        }
      }
    }
  }, {
    "type": "organization_resource",
    "relations": {
      "has_delete": {
        "tupleToUserset": {
          "tupleset": {
            "object": "",
            "relation": "parent_org"
          },
          "computedUserset": {
            "object": "",
            "relation": "has_delete"
          }
        }
      },
      "has_read": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "has_write"
            }
          }, {
            "tupleToUserset": {
              "tupleset": {
                "object": "",
                "relation": "parent_org"
              },
              "computedUserset": {
                "object": "",
                "relation": "has_read"
              }
            }
          }]
        }
      },
      "has_write": {
        "tupleToUserset": {
          "tupleset": {
            "object": "",
            "relation": "parent_org"
          },
          "computedUserset": {
            "object": "",
            "relation": "has_write"
          }
        }
      },
      "parent_org": {
        "this": {}
      }
    },
    "metadata": {
      "relations": {
        "has_delete": {
          "directly_related_user_types": []
        },
        "has_read": {
          "directly_related_user_types": []
        },
        "has_write": {
          "directly_related_user_types": []
        },
        "parent_org": {
          "directly_related_user_types": [{
            "type": "organization"
          }]
        }
      }
    }
  }, {
    "type": "super_team",
    "relations": {
      "has_delete": {
        "computedUserset": {
          "object": "",
          "relation": "manager_user"
        }
      },
      "has_read": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "has_write"
            }
          }, {
            "computedUserset": {
              "object": "",
              "relation": "read_user"
            }
          }]
        }
      },
      "has_write": {
        "union": {
          "child": [{
            "computedUserset": {
              "object": "",
              "relation": "manager_user"
            }
          }, {
            "computedUserset": {
              "object": "",
              "relation": "write_user"
            }
          }]
        }
      },
      "manager_user": {
        "this": {}
      },
      "read_user": {
        "this": {}
      },
      "write_user": {
        "this": {}
      }
    },
    "metadata": {
      "relations": {
        "has_delete": {
          "directly_related_user_types": []
        },
        "has_read": {
          "directly_related_user_types": []
        },
        "has_write": {
          "directly_related_user_types": []
        },
        "manager_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        },
        "read_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        },
        "write_user": {
          "directly_related_user_types": [{
            "type": "user"
          }]
        }
      }
    }
  }, {
    "type": "user",
    "relations": {}
  }]
}

Allow deleting/writing the same tuple key in the same Write call

Checklist

Describe the problem you'd like to have solved

If we want to change the context values of a tuple, I need to delete/write the tuple in the same write() call.

However, OpenFGA tries to write it first, and it returns an error as it's duplicated.

Describe the ideal solution

We should first process deletes and then writes.

Alternatives and current workarounds

Make 2 write calls in different transactions.

Additional context

No response

Inherence permissions for roles

Hi,

I'm trying to model authorization model with nested roles. For example, role:2 have editor relation with document:exp, and role:1 his parent of role:2, then role:1 has a permissions to edit document:exp.

I have tried to write the next DSL, but I got an error (editor relation used inside from allows only direct relation.):
image

There is some walk around for this error? or other way to model it?

Thanks

playground: "thing" labeled "user" in tuple/assertion not necessarily a user

When you add tuples or assertions in the playground, the text field for the thing that is related to the object is labeled "user".

In the default authorization model, which contains, amongst others, types "user", "folder" and "doc", this is ok in some cases (like e.g. tuple user:u01 owner doc:d03). However, in other cases, I think it's inappropriate (like e.g. tuple folder:f05 parent folder:f03, because folder:f05 is not a user).

The concept of tuples in openfga looks very similar to RDF with its triples containing a subject, a predicate and an object. So, why not call the first part of the openfga tuple, a subject, which is a more general term as the (in some cases inappropriate) user?

I came along openfga only recently, so please bear with me, if my suggestion doesn't make sense.

Yugabyte Datastore for Multi Region Support

Checklist

Describe the problem you'd like to have solved

Hi, I am currently trying to understand the support OpenFGA has for distributed databases such as Yugabyte or CockroachDB. We are trying to build a global auth system that requires a fast and reliable data backend for storage and data access. While I have gone through the documentation of OpenFGA, I could not find a source where multi-region support has been talked about. Clarification on the same would be much appreciated

Describe the ideal solution

Use a distributed database such as Yugabyte or CockroachDB as the backend for OpenFGA

Alternatives and current workarounds

No response

Additional context

No response

[Request] Allow non-transactional writes (make WriteRequest idempotent)

It would be nice that sending the same write request twice would result in the same outcome. However for the second call, the SDK will return an error saying that

cannot write a tuple which already exists: <tuple>

However, as a user I'd expect this call to succeed as the desired end state is that the tuple exists, so if it already exists before I make the call, this is essentially a no-op to end up in the desired end state, rather than a failure/error.

Add creation and last update dates to authorization models

So far, only stores have both creation and last update dates. Unfortunatly, regarding authorization models, it is impossible to get a specific version without knowing its ID, as the list authorization models endpoint does not indicate how models are ordered before being retrieved.

A successful but quite easy-to-implement solution would retrieve an authorization model creation date aside with its last update one, which could be the same date as the creation date if no update has been performed yet. That way, we could list authorization models and know which one is the latest.

Please let know if more explanations have to be provided, cheers!

[Playground] Support AND and BUT NOT operators in the graph

Hi!
I'm trying to implement a model with Blocklists on different levels of my hierarchy, in order to define something like:

user:a is admin on archive:xxx of tenant:yyy (so she should have access to all documents inside all folders in the archive:xxx)
but must not have access to documents inside folder:zzz (which is part of archive:xxx)

I tried with a model like this:

type user

type tenant
  relations
    define deny as self

    define admin as self but not deny
    define editor as self but not deny
    define reader as self but not deny

type archive
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as self or admin from parent but not deny
    define editor as self or admin or editor from parent but not deny
    define reader as self or editor or reader from parent but not deny

type folder
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as self or admin from parent but not deny
    define editor as self or admin or editor from parent but not deny
    define reader as self or editor or reader from parent but not deny

type doc
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as self or admin from parent but not deny
    define editor as self or admin or editor from parent but not deny
    define reader as self or editor or reader from parent but not deny

Unfortunately, the playground wouldn't let me save my model, and all the but not deny were marked as syntax errors.

So I tried to be smart and changed my model to this:

type user

type tenant
  relations
    define deny as self

    define admin as self but not deny
    define editor as self but not deny
    define reader as self but not deny

type archive
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as admin_allow but not deny
    define admin_allow as self or admin from parent
    define editor as editor_allow but not deny
    define editor_allow as self or admin or editor from parent
    define reader as reader_allow but not deny
    define reader_allow as self or editor or reader from parent

type folder
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as admin_allow but not deny
    define admin_allow as self or admin from parent
    define editor as editor_allow but not deny
    define editor_allow as self or admin or editor from parent
    define reader as reader_allow but not deny
    define reader_allow as self or editor or reader from parent

type doc
  relations
    define parent as self
    define deny as self or deny from parent

    define admin as admin_allow but not deny
    define admin_allow as self or admin from parent
    define editor as editor_allow but not deny
    define editor_allow as self or admin or editor from parent
    define reader as reader_allow but not deny
    define reader_allow as self or editor or reader from parent

Now the syntax is correct, but when I try to run some assertions I get the error AND and BUT NOT operators are currently not supported on this graph.
Am I doing something wrong? Is there any other way to do what I'm trying to do?

Thanks!

EDIT: I'll add an example that hopefully clarifies what I'm trying to do.
My data is something like:

tenant:xxx
|
|_archive:archive1
| |
| |_folder:folder1-1
| | |
| | |_doc:doc1-1-1
| | |_doc:doc1-1-2
| | 
| |_folder:folder1-2
| | |
| | |_doc:doc1-2-1
| |_|_doc:doc1-2-2
| 
|_archive:archive2
| |
| |_folder:folder2-1
| | |
| | |_doc:doc2-1-1
| | |_doc:doc2-1-2
| | 
| |_folder:folder2-2
| | |
| | |_doc:doc2-2-1
|_|_|_doc:doc2-2-2

I'd like to be able to do something like this:

user:alice is reader on tenant:xxx, so she is reader on both archive:archive1 and archive:archive2 and their subtrees.
user:alice MUST NOT read folder:folder2-2 and its documents, namely doc:doc2-2-1 and doc:doc2-2-2, so she is deny on folder:folder2-2

Native Support for Google Cloud Spanner

I'm wondering if you have considered adding Google Cloud Spanner support for OpenFGA?

It has global strong transactional consistency, extremely performant, 99.999 SLA, and it has zero downtime schema changes (everything you want for OpenFGA). It is also more cost effective to run spanner than it is to run Cloud SQL (Much cheaper to run ever since Spanner changed their pricing model - $65 dollars a month for about 1k reads / second and 200 writes / second with no downtime upgrades for more).

We are thinking of using OpenFGA with cloud spanner through the PGAdapter (postgres adapter), which is possible because it supports pgx connections, however that is extra overhead and we would love it if it was possible to use spanner with openfga without any sidecar proxy adapter infra to manage.

Spanner + OpenFGA work really well together

Screenshot 2023-06-13 at 5 28 31 pm

Modeling access to a sub-set of a hierarchy

I have been using openFGA for a while to model some moderately complex requirements, but I feel I am stuck now at modeling something that's basic in g-drive

### Access control on a sub-chain
Assume a hierarchy like below, and the access provided at each level

  • Folder1 - User is Owner
    • Folder2 - User can_write as owner from parent
      • Folder3 - in g-drive, we can remove inherited access (owner here), and give some other access, say we now make user a "viewer"
        • Folder4 - as per g-drive logic, no can_write access to user at this point, but in OpenFGA user will have can_write access
          • Folder5 - User granted Ownership of Folder 5
            • Folder 6 - User has can_write of Folder 6

And we can repeat this as many times as possible, creating sub-chains that behave differently (Folder-1 & 2 user has WRITE access, then folder 3 and 4 user has VIEW access, and then again WRITE access)

Is there a way to model this in OpenFGA?

Also, is there any way in OpenFGA to implement 'least privilege model' - on a resource, if as a member of User Group 1 user has WRITE access, and as member of User Group 2 same user has VIEW access, then we want to only allow VIEW access to user.

Many thanks for reading the problem statement.

[Playground] The "COPY AS FRIENDLY DSL" button in the playground doesn't give me the newly saved DSL

OpenFGA v0.2.4

The "COPY AS FRIENDLY DSL" button in the playground doesn't give me the newly saved DSL

  1. Create a new Store
  2. Copy the DSL using the "COPY AS FRIENDLY DSL" button
type group
  relations
    define member as self
type resource
  relations
    define writer as self
    define reader as self or writer
  1. Added and SAVE a new type "dog"
type group
  relations
    define member as self
type resource
  relations
    define writer as self
    define reader as self or writer
type dog
  relations
    define owner as self
  1. "COPY AS FRIENDLY DSL" returns the following, dog is missing;
type group
  relations
    define member as self
type resource
  relations
    define writer as self
    define reader as self or writer

Copy as JSON works

{
  "type_definitions": [
    {
      "type": "group",
      "relations": {
        "member": {
          "this": {}
        }
      }
    },
    {
      "type": "resource",
      "relations": {
        "writer": {
          "this": {}
        },
        "reader": {
          "union": {
            "child": [
              {
                "this": {}
              },
              {
                "computedUserset": {
                  "object": "",
                  "relation": "writer"
                }
              }
            ]
          }
        }
      }
    },
    {
      "type": "dog",
      "relations": {
        "owner": {
          "this": {}
        }
      }
    }
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.