Modeling Roles and Permissions
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.
In this guide you will learn how to model roles and permissions model within Auth0 FGA using the authorization model and relationship tuple.
- Roles are assigned to usersor a group of users, where any user can have more than one role (
editor
,owner
, etc..). - Permissions are what allows users to access certain objects based on their specific roles (
device_renamer
,channel_archiver
, etc..).
For example, the role viewer
of a trip
can have permissions to view bookings or the role owners
can have permissions to add/view bookings to a trip.
When trying to create a role and permissions model within Auth0 FGA.:
- Create roles by creating relations that can be directly assigned to users
- Assign permissions by creating relations that users get through other relations
For example:
- Grant someone an
admin
role that canedit
andread
adocument
- Grant someone a
security_guard
role that canlive_video_viewer
on adevice
- Grant someone a
viewer
role that canview_products
on ashop
There are advantages to implementing roles and permissions within Auth0 FGA, such as:
- Breaking down existing roles to have more fine grained permissions. This allows your application to check whether a user has access to a certain object without having to explicitly check that specific users role.
- Introduce new roles/permissions or consolidate roles without affecting your application behavior. For example: if in your app all the checks are for the fine permissions
check('bob', 'booking_adder', 'trip:Europe')
instead ofcheck('bob', 'owner', 'trip:Europe')
, and then you later decideowners
can no longer add bookings to atrip
, you can remove the relation within thetrip
type with no code changes in your application, and all the permissions will automatically honor the change.
Before you start
In order to understand this guide correctly you must be familiar with some Auth0 FGA Concepts and know how to develop the things that we will list below.
Assume that you have the following authorization model.
You have a type called trip
that users can be related to as viewer
and/or an owner
.
You have a type called
trip
that users can be related to as viewer
and/or an owner
.- DSL
- JSON
type trip
relations
define owner as self
define viewer as self
{
"type_definitions": [
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
}
}
}
]
}
In addition, you will need to know the following:
Modeling Basics
You need to know how to create an authorization model and create a relationship tuple to grant a user access to an object. Learn more →
Auth0 FGA Concepts
- A Type: a class of objects that have similar characteristics
- A User: an entity in the system that can be related to an object
- 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
- An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
- A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in Auth Auth0 FGA
- A Relationship: Auth0 FGA will be called to check if there is a relationship between a user and an object, indicating that the access is allowed
- Direct Relationship Keyword: The
self
keyword can be used to indicate direct relationships between users and objects - A Check API Request the Check API Request is used to check for relationships between users and objects
Step by Step
To illustrate modeling Roles and Permissions in Auth0 FGA, we will use a trip booking system where you can have owners
and/or viewers
that can have more granular permissions such as adding bookings to a trip or viewing bookings on it.
In order to represent this, we need to:
- Understand how roles are related to direct relations for our trip booking system
- Adding implied relations to existing authorization model to define permissions for bookings
- Checking user roles and their permissions based on *relationship tuples* for direct and implied relations
01. Understand how roles work within our trip booking system
Relating roles within Auth0 FGA can be best described as the following: Roles are relations that can be directly assigned to users. Looking at our authorization model, our roles would then be owner
and viewer
. Meaning that a specific user can be an owner
and/or a viewer
.
- DSL
- JSON
type trip
relations
define owner as self
define viewer as self
{
"type_definitions": [
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
}
}
}
]
}
02. Adding permissions for bookings
Permissions within Auth0 Fine Grained Authorization (FGA) can be best described as the following: Permissions are relations that users get only through other relations. To represent permissions, we avoid adding the direct relationship keyword (self
) to the relation in the authorization model. Instead, we define the relation from other relations to indicate that it is a permission granted to and implied from a different relation.
To add permissions related to bookings, we can add new relations to the trip
object type denoting the various actions a user can take on trips
(view, edit, delete, rename, etc...)
To allow viewers
of a trip
to have permissions to view bookings and owners
to have permissions to add/view bookings, we would modify the type as the following:
- DSL
- JSON
type trip
relations
define owner as self
define viewer as self
define booking_adder as owner
define booking_viewer as viewer or owner
{
"type_definitions": [
{
"type": "trip",
"relations": {
"owner": {
"this": {}
},
"viewer": {
"this": {}
},
"booking_adder": {
"computedUserset": {
"relation": "owner"
}
},
"booking_viewer": {
"union": {
"child": [
{
"computedUserset": {
"relation": "viewer"
}
},
{
"computedUserset": {
"relation": "owner"
}
}
]
}
}
}
}
]
}
Note: notice how both
booking_viewer
andbooking_adder
don't have theself
syntax, this is to ensure that the relation can only be assigned through the role and not directly.
03. Checking user roles and their permissions
Now that our type definitions reflects the roles and permissions on how bookings can be viewed/added. Let's create relationship tuples to assign roles to users and then checkif users have the proper permissions.
Let us create two relationship tuples:
- that gives bob the role of
viewer
ontrip
: Europe. - that gives alice the role of
owner
ontrip
: Europe.
- Node.js
- Go
- .NET
- curl
- Pseudocode
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,
});
await fgaClient.write({
writes: {
tuple_keys: [
// Add bob as viewer on trip:Europe
{ user: 'bob', relation: 'viewer', object: 'trip:Europe'},
// Add alice as owner on trip:Europe
{ user: 'alice', relation: 'owner', object: 'trip:Europe'}
]
}
});
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.WriteRequest{
Writes: &fgaSdk.TupleKeys{
TupleKeys: []fgaSdk.TupleKey {
{
// Add bob as viewer on trip:Europe
User: fgaSdk.PtrString("bob"),
Relation: fgaSdk.PtrString("viewer"),
Object: fgaSdk.PtrString("trip:Europe"),
},
{
// Add alice as owner on trip:Europe
User: fgaSdk.PtrString("alice"),
Relation: fgaSdk.PtrString("owner"),
Object: fgaSdk.PtrString("trip:Europe"),
},
},
},
}
_, response, err := fgaClient.Auth0FgaApi.Write(context.Background()).Body(body).Execute()
if err != nil {
// .. Handle error
}
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);
}
}
await fgaClient.Write(new WriteRequest{
Writes = new TupleKeys(new List<TupleKey>() {
// Add bob as viewer on trip:Europe
new() { User = "bob", Relation = "viewer", Object = "trip:Europe" },
// Add alice as owner on trip:Europe
new() { User = "alice", Relation = "owner", Object = "trip:Europe" }
})
});
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/write \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"writes": { "tuple_keys" : [{"user":"bob","relation":"viewer","object":"trip:Europe"},{"user":"alice","relation":"owner","object":"trip:Europe"}] }}'
write([
// Add bob as viewer on trip:Europe
{
"user":"bob",
"relation":"viewer",
"object":"trip:Europe"
},
// Add alice as owner on trip:Europe
{
"user":"alice",
"relation":"owner",
"object":"trip:Europe"
}
])
Now we can check: is bob allowed to view bookings on trip Europe?
- 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: 'bob',
relation: 'booking_viewer',
object: 'trip:Europe',
},});
// 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.CheckRequest{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("bob"),
Relation: fgaSdk.PtrString("booking_viewer"),
Object: fgaSdk.PtrString("trip:Europe"),
},
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 CheckRequest(new TupleKey {
User = "bob",
Relation = "booking_viewer",
Object = "trip:Europe"
});
// 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":"bob","relation":"booking_viewer","object":"trip:Europe"}}'
# Response: {"allowed":true}
check(
"bob", // check if the user `bob`
"booking_viewer", // has an `booking_viewer` relation
"trip:Europe", // with the object `trip:Europe`
);
Reply: true
is bob related to trip:Europe as booking_viewer?
# Response: A green path from the user to the object indicating that the response from the API is `{"allowed":true}`
bob is a booking_viewer
because of the following chain of resolution:
- bob is a
viewer
ontrip
: Europe - Any user related to the object
trip:
Europe asviewer
is also related as abooking_viewer
(i.eusersRelatedToObjectAs: viewer
) - Therefore, all
viewers
on a giventrip
arebooking_viewers
To confirm that bob is not allowed to add bookings on trip Europe, we can do the following check:
- 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: 'bob',
relation: 'booking_adder',
object: 'trip:Europe',
},});
// allowed = false
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.CheckRequest{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("bob"),
Relation: fgaSdk.PtrString("booking_adder"),
Object: fgaSdk.PtrString("trip:Europe"),
},
data, response, err := fgaClient.Auth0FgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: false }
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 CheckRequest(new TupleKey {
User = "bob",
Relation = "booking_adder",
Object = "trip:Europe"
});
// response.Allowed = false
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":"bob","relation":"booking_adder","object":"trip:Europe"}}'
# Response: {"allowed":false}
check(
"bob", // check if the user `bob`
"booking_adder", // has an `booking_adder` relation
"trip:Europe", // with the object `trip:Europe`
);
Reply: false
is bob related to trip:Europe as booking_adder?
# Response: A red object indicating that the response from the API is `{"allowed":false}`
We can also check: is alice allowed to view and add bookings on trip Europe?
- 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: 'alice',
relation: 'booking_viewer',
object: 'trip:Europe',
},});
// 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.CheckRequest{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("alice"),
Relation: fgaSdk.PtrString("booking_viewer"),
Object: fgaSdk.PtrString("trip:Europe"),
},
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 CheckRequest(new TupleKey {
User = "alice",
Relation = "booking_viewer",
Object = "trip:Europe"
});
// 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":"alice","relation":"booking_viewer","object":"trip:Europe"}}'
# Response: {"allowed":true}
check(
"alice", // check if the user `alice`
"booking_viewer", // has an `booking_viewer` relation
"trip:Europe", // with the object `trip:Europe`
);
Reply: true
is alice related to trip:Europe as booking_viewer?
# Response: A green path from the user to the object indicating that the response from the API is `{"allowed":true}`
- 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: 'alice',
relation: 'booking_adder',
object: 'trip:Europe',
},});
// 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.CheckRequest{
TupleKey: &fgaSdk.TupleKey{
User: fgaSdk.PtrString("alice"),
Relation: fgaSdk.PtrString("booking_adder"),
Object: fgaSdk.PtrString("trip:Europe"),
},
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 CheckRequest(new TupleKey {
User = "alice",
Relation = "booking_adder",
Object = "trip:Europe"
});
// 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":"alice","relation":"booking_adder","object":"trip:Europe"}}'
# Response: {"allowed":true}
check(
"alice", // check if the user `alice`
"booking_adder", // has an `booking_adder` relation
"trip:Europe", // with the object `trip:Europe`
);
Reply: true
is alice related to trip:Europe as booking_adder?
# Response: A green path from the user to the object indicating that the response from the API is `{"allowed":true}`
alice is a booking_viewer
and booking_adder
because of the following chain of resolution:
- alice is a
owner
ontrip
: Europe - Any user related to the object
trip:
Europe asowner
is also related as abooking_viewer
- Any user related to the object
trip:
Europe asowner
is also related as abooking_adder
- Therefore, all
owners
on a giventrip
arebooking_viewers
andbooking_adders
on that trip
caution
Note: Make sure to use unique ids for each object and user within your application domain when creating relationship tuples for Auth0 Fine Grained Authorization (FGA). We are using first names and simple ids to just illustrate an easy-to-follow example.
Related Sections
Learn about how to represent a concentric relationships in Auth0 FGA.
See how to indicate that editors are commenters and viewers in Google Drive.