Auth0 Fine Grained Authorization (FGA) Concepts
note
Please note that at this point in time, it is not considered production-ready and does not come with any SLAs; availability and uptime are not guaranteed. Limitations of Auth0 FGA during the Developer Community Preview can be found here.
The Auth0 FGA service answers authorization checks by determining whether a relationship exists between an object and a user and takes into consideration the authorization model of the system and the relationship tuples present in the system at that time in order to make a decision.
In this guide you will learn about the most relevant FGA concepts, such as a type or an authorization model, and you will be able to explore them using the FGA playground.
What is a type?
A type is a class of objects that have similar characteristics.
Examples of types:
workspace
repository
organization
document
What is a type definition?
A type definition is a configuration that defines all possible relations a user or another object can have in relation to this type.
Code snippet below is an example of a type definition:
- DSL
- JSON
type document
relations
define viewer as self
define commenter as self
define editor as self
define owner as self
{
"type": "document",
"relations": {
"viewer": {
"this": {}
},
"commenter": {
"this": {}
},
"editor": {
"this": {}
},
"owner": {
"this": {}
}
}
}
What is an authorization model?
An authorization model is a combination of one or more type definitions. This is used to define the permission model of a system.
Code snippet below is an example of an authorization model:
- DSL
- JSON
type document
relations
define viewer as self
define commenter as self
define editor as self
define owner as self
type domain
relations
define member as self
{
"type_definitions": [
{
"type": "document",
"relations": {
"viewer": {
"this": {}
},
"commenter": {
"this": {}
},
"editor": {
"this": {}
},
"owner": {
"this": {}
}
}
},
{
"type": "domain",
"relations": {
"member": {
"this": {}
}
}
}
]
}
Authorization model, together with relationship tuples, allow determination of whether a relationship exists between a user and an object.
The Auth0 Fine Grained Authorization (FGA) service has two different syntaxes to define the authorization model:
- A JSON syntax accepted by the Auth0 FGA API that follows closely the original syntax discussed in the Zanzibar Paper. See Equivalent Zanzibar Concepts.
- A DSL that we believe is easier to use and is used in the Auth0 FGA Playground to help with modeling. This is translated to the API-supported syntax before being sent to the API.
Learn more about the Auth0 FGA Configuration Language.
What is a store?
A store is a Auth0 Fine Grained Authorization (FGA) organization entity that owns authorization model.
A store contains all your data, including authorization model and relationship tuples.
What is an object?
An object represents an entity in the system. We can define how various users have a relationship to it through relationship tuples and the authorization model.
The object name is a combination of the type and an identifier of the object.
For example:
workspace:fb83c013-3060-41f4-9590-d3233a67938f
repository:auth0/express-jwt
organization:org_ajUc9kJ
document:new-roadmap
User, relation and object are the building blocks for relationship tuples.
For more information, please see Modeling Basics.
What is a user?
A user is an entity in the system that can be related to an object.
A user is
- any user: e.g.
anne
or4179af14-f0c0-4930-88fd-5570c7bf6f59
- any object: e.g.
workspace:fb83c013-3060-41f4-9590-d3233a67938f
,repository:auth0/express-jwt
ororganization:org_ajUc9kJ
- a group or a set of users (also called a userset): e.g.
organization:org_ajUc9kJ#members
, which represents the set of users related to the objectorganization:org_ajUc9kJ
asmember
- everyone, using the special syntax:
*
User, relation and object are the building blocks for relationship tuples.
For more information, please see Modeling Basics.
What is a relation?
A relation is a string defined in the type definition of an authorization model that defines the possibility of a relationship between objects of this type and other users in the system.
Examples of relation:
- User can be a
reader
a document - Team can
administer
a repo - User can be a
member
of a team
What is a relation definition?
A relation definition lists the conditions or requirements under which this relationship would be possible.
For example:
editor
describing a possible relationship between a user and an object in thedocument
type allows the following:- user identifier to object relationship: the user id
anne
is related to the objectdocument:roadmap
aseditor
- object to object relationship: the object
application:ifft
is related to the objectdocument:roadmap
aseditor
- userset to object relationship: the userset
organization:auth0.com#member
is related todocument:roadmap
aseditor
- indicating that the set of users who are related to the object
organization:auth0.com
asmember
are related to the objectdocument:roadmap
aseditor
s - this allows for potential solutions to use-cases like sharing a document internally with all members of a company or a team
- indicating that the set of users who are related to the object
- everyone to object relationship: everyone (
*
) is related todocument:roadmap
aseditor
- this allows for solution to use-cases such as having a document publicly editable
- user identifier to object relationship: the user id
These would be defined in the authorization model as such:
- DSL
- JSON
type document
relations
define viewer as self
define commenter as self
define editor as self
define owner as self
{
"type_definitions": [
{
"type": "document",
"relations": {
"viewer": {
"this": {}
},
"commenter": {
"this": {}
},
"editor": {
"this": {}
},
"owner": {
"this": {}
}
}
}
]
}
info
In the configuration of the document type, we have four relations: viewer
, commenter
, editor
and owner
.
User, relation and object are the building blocks for relationship tuples.
For more information, please see Modeling Basics.
What is a relationship tuple?
A relationship tuple is a grouping consisting of a user, a relation and an object stored in Auth0 FGA .
A relationship tuple consists of a grouping of:
- user, e.g.
anne
,3f7768e0-4fa7-4e93-8417-4da68ce1846c
,workspace:auth0
orfolder:planning#editor
- relation, e.g.
editor
,member
orparent_workspace
- object, e.g
repo:auth0/express_jwt
,domain:auth0.com
orchannel:marketing
An authorization model, together with relationship tuples, allow the determination of whether a relationship exists between a user and an object.
Throughout the documentation, you will encounter relationship tuples represented as:
[
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
]
For more information, please see Modeling Basics.
What is a relationship?
A relationship is the realization of a relation between a user and an object.
An authorization model, together with relationship tuples, allow the determination of whether a relationship exists between a user and an object. Relationships may be classified as direct or implied.
What are direct and implied relationships?
A direct relationship R between user X and object Y means the relationship tuple (user=X, relation=R, object=Y) exists, and the Auth0 FGA authorization model for that relation allows this direct relationship (by use of self
).
An implied relationship R exists between user X and object Y if user X is related to an object Z that is in direct or implied relationship with object Y, and the Auth0 FGA authorization model allows it.
self
).anne
has a direct relationship withdocument:new-roadmap
asviewer
if the type definition allows it (allowsself
), and one of the following relationship tuples exist:[
// Anne is directly related to the document
{
"user": "anne",
"relation": "viewer",
"object": "document:new-roadmap",
},
][
// Everyone (`*`) is directly related to the document
{
"user": "*",
"relation": "viewer",
"object": "document:new-roadmap",
},
][
// The userset is directly related to this document
{
"user": "team:product#member",
"relation": "viewer",
"object": "document:new-roadmap",
},
// AND Anne is a member of a userset (e.g. team:product#member)
{
"user": "anne",
"relation": "member",
"object": "team:product#member",
},
]
anne
has an implied (also called computed) relationship withdocument:new-roadmap
asviewer
if the type definition allows it, and the presence of relationship tuples satisfying the relationship exist.For example, assuming the following type definition:
- DSL
- JSON
type document
relations
define viewer as self or editor
define editor as self{
"type_definitions": [
{
"type": "document",
"relations": {
"viewer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
}
]
}
},
"editor": {
"this": {}
}
}
}
]
}And assuming the following relationship tuple exists in the system:
[
{
"user": "anne",
"relation": "editor",
"object": "document:new-roadmap",
},
]In this case, the relationship between
anne
anddocument:new-roadmap
as aviewer
is implied from theeditor
relationshipanne
has with that same document. There does not exist any relationship tuple indicating thatanne
is directly related to the document as aviewer
. Thus, the following request to check whether a viewer relationship exists betweenanne
anddocument:new-roadmap
will returntrue
.- Node.js
- Go
- .NET
- curl
- Pseudocode
- Playground
Initialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
// import the SDK
const { Auth0FgaApi } = require('@auth0/fga');
// Initialize the SDK
const fgaClient = new Auth0FgaApi({
environment: process.env.FGA_ENVIRONMENT,
storeId: process.env.FGA_STORE_ID,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
});
// Run a check
const { allowed } = await fgaClient.check({
tuple_key: {
user: 'anne',
relation: 'viewer',
object: 'document:new-roadmap',
},});
// allowed = trueInitialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
import (
fgaSdk "github.com/auth0-lab/fga-go-sdk"
"os"
)
func Main() {
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
Environment: os.Getenv("FGA_ENVIRONMENT"),
StoreId: os.Getenv("FGA_STORE_ID"),
ClientId: os.Getenv("FGA_CLIENT_ID"),
ClientSecret: os.Getenv("FGA_CLIENT_SECRET"),
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequestParams{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("anne"),
Relation: fgaSdk.PtrString("viewer"),
Object: fgaSdk.PtrString("document:new-roadmap"),
},
data, response, err := fgaClient.Auth0FgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }Initialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
// import the SDK
using Auth0.Fga.Api;
using Auth0.Fga.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
var storeId = Environment.GetEnvironmentVariable("FGA_STORE_ID");
var environment = Environment.GetEnvironmentVariable("FGA_ENVIRONMENT")
var configuration = new Configuration(storeId, environment) {
ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"),
ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET"),
};
var fgaClient = new Auth0FgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check(new CheckRequestParams(new TupleKey {
User = "anne",
Relation = "viewer",
Object = "document:new-roadmap"
});
// response.Allowed = trueGet the Bearer Token and set up the FGA_API_URL environment variable
# Not needed when calling the Playground API
curl -X POST \
https://fga.us.auth0.com/oauth/token \
-H 'content-type: application/json' \
-d '{"client_id":"'$FGA_CLIENT_ID'","client_secret":"'$FGA_CLIENT_SECRET'","audience":"https://api.us1.fga.dev/","grant_type":"client_credentials"}'
# The response will be returned in the form
# {
# "access_token": "eyJ...Ggg",
# "expires_in": 86400,
# "scope": "read:tuples write:tuples check:tuples ... write:authorization-models",
# "token_type": "Bearer"
# }
# Store this `access_token` value in environment variable `FGA_BEARER_TOKEN`
# For non-playground environment
FGA_API_URL='https://api.us1.fga.dev'
# For playground environment
# FGA_API_URL='https://api.playground.fga.dev'curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"tuple_key":{"user":"anne","relation":"viewer","object":"document:new-roadmap"}}'
# Response: {"allowed":true}check(
"anne", // check if the user `anne`
"viewer", // has an `viewer` relation
"document:new-roadmap", // with the object `document:new-roadmap`
);
Reply: trueis anne related to document:new-roadmap as viewer?
# Response: A green path from the user to the object indicating that the response from the API is `{"allowed":true}`
What is a check request?
A check request is a call to the Auth0 Fine Grained Authorization (FGA) API endpoint that returns whether the user has a certain relationship with an object.
This can be done using the check
methods in the Auth0 FGA SDKs (JavaScript SDK/Go SDK/.NET SDK) or by manually calling the check endpoint using curl or in your code.
The check endpoint responds with { "allowed": true }
if a relationship exists, and with { "allowed": false }
if the relationship does not.
For example, the following will check whether anne
has viewer
relation to document:new-roadmap
:
- Node.js
- Go
- .NET
- curl
- Pseudocode
- Playground
Initialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
// import the SDK
const { Auth0FgaApi } = require('@auth0/fga');
// Initialize the SDK
const fgaClient = new Auth0FgaApi({
environment: process.env.FGA_ENVIRONMENT,
storeId: process.env.FGA_STORE_ID,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
});
// Run a check
const { allowed } = await fgaClient.check({
tuple_key: {
user: 'anne',
relation: 'viewer',
object: 'document:new-roadmap',
},});
// allowed = true
Initialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
import (
fgaSdk "github.com/auth0-lab/fga-go-sdk"
"os"
)
func Main() {
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
Environment: os.Getenv("FGA_ENVIRONMENT"),
StoreId: os.Getenv("FGA_STORE_ID"),
ClientId: os.Getenv("FGA_CLIENT_ID"),
ClientSecret: os.Getenv("FGA_CLIENT_SECRET"),
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequestParams{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("anne"),
Relation: fgaSdk.PtrString("viewer"),
Object: fgaSdk.PtrString("document:new-roadmap"),
},
data, response, err := fgaClient.Auth0FgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }
Initialize the SDK
// FGA_ENVIRONMENT can be "us" (default if not set) for Developer Community Preview or "playground" for the Playground API
// import the SDK
using Auth0.Fga.Api;
using Auth0.Fga.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
var storeId = Environment.GetEnvironmentVariable("FGA_STORE_ID");
var environment = Environment.GetEnvironmentVariable("FGA_ENVIRONMENT")
var configuration = new Configuration(storeId, environment) {
ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"),
ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET"),
};
var fgaClient = new Auth0FgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check(new CheckRequestParams(new TupleKey {
User = "anne",
Relation = "viewer",
Object = "document:new-roadmap"
});
// response.Allowed = true
Get the Bearer Token and set up the FGA_API_URL environment variable
# Not needed when calling the Playground API
curl -X POST \
https://fga.us.auth0.com/oauth/token \
-H 'content-type: application/json' \
-d '{"client_id":"'$FGA_CLIENT_ID'","client_secret":"'$FGA_CLIENT_SECRET'","audience":"https://api.us1.fga.dev/","grant_type":"client_credentials"}'
# The response will be returned in the form
# {
# "access_token": "eyJ...Ggg",
# "expires_in": 86400,
# "scope": "read:tuples write:tuples check:tuples ... write:authorization-models",
# "token_type": "Bearer"
# }
# Store this `access_token` value in environment variable `FGA_BEARER_TOKEN`
# For non-playground environment
FGA_API_URL='https://api.us1.fga.dev'
# For playground environment
# FGA_API_URL='https://api.playground.fga.dev'
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"tuple_key":{"user":"anne","relation":"viewer","object":"document:new-roadmap"}}'
# Response: {"allowed":true}
check(
"anne", // check if the user `anne`
"viewer", // has an `viewer` relation
"document:new-roadmap", // with the object `document:new-roadmap`
);
Reply: true
is anne related to document:new-roadmap as viewer?
# Response: A green path from the user to the object indicating that the response from the API is `{"allowed":true}`
For more information, please see Comparison between check, read and expand and Check API Request Documentation.
What are contextual tuples?
Contextual tuples are tuples that are sent alongside a check request, and only exist within the context of that particular request.
Unlike relationship tuples, they are not written to the system state. If contextual tuples are sent alongside a check request, they are treated as if they are true (treated as as if they are relationship tuples that have been written to the system state).
For more information, please see Contextual and Time-Based Authorization, Authorization Through Organization Context and Check API Request Documentation.
How do I represent "everyone"?
In Auth0 Fine Grained Authorization (FGA) the special *
syntax means everyone when used as user in a relationship tuple.
*
syntax means everyone when used as user in a relationship tuple.For example, in a case where you would like to indicate a certain document document:new-roadmap
is publicly writable (i.e. has everyone as an editor), you can add the following relationship tuple:
[
{
"user": "*",
"relation": "editor",
"object": "document:new-roadmap",
},
]
Note that *
has no special meaning when used in other contexts. For example, workspace:*
as a user or object means a single object with the type workspace
and the object_id the string *
.
For more information, please see Modeling Public Access and Advanced Modeling: Modeling Google Drive.