FQL v4 will be decommissioned on June 30, 2025. Ensure that you complete your migration from FQL v4 to FQL v10 by that date. Fauna accounts created after August 21, 2024 must use FQL v10. These accounts will not be able to run FQL v4 queries or access the v4 Dashboard. For more details, see the v4 EOL announcement and migration guide. Contact support@fauna.com with any questions. |
Role-based authentication
The following procedure demonstrates setting up User-defined roles and assigning them to UDFs for better data security.
For purposes of illustration, this tutorial imagines an online service called Weather Data, in which users can read about and report on weather information around the world. The service has three kinds of users:
-
Readers, who can only read the available information.
-
Reporters, who can read from and write to the database.
-
Managers, who can create new users and also have read/write access to the database.
The service has three UDFs:
-
Get_weather_reports
, which anyone can call. -
Create_weather_report
, which only Reporters can call. -
Create_weather_user
, which only Managers can call.
To follow along with this procedure, you need a Fauna account. For help with setting up a Fauna account, see the Dashboard quick start.
Step 1: Create a new database
Navigate to the Fauna Dashboard and create a new database called
weather_data
.
Once your database is created, you can interact with it either with a
driver, with the Dashboard Shell, or with the
fauna-shell
command-line
tool. All of the subsequent steps in this example provide FQL queries
in each supported language, well as FQL for use in the
Dashboard Shell or fauna-shell
.
Step 2: Create two new collections
Create a new collection called weather_reports
and another one
called weather_users
:
[
{
ref: Collection("weather_reports"),
ts: 1648443407640000,
history_days: 30,
name: 'weather_reports'
},
{
ref: Collection("weather_users"),
ts: 1648443407640000,
history_days: 30,
name: 'weather_users'
}
]
[{'ref': Ref(id=weather_reports, collection=Ref(id=collections)), 'ts': 1650393153190000, 'history_days': 30, 'name': 'weather_reports'}, {'ref': Ref(id=weather_users, collection=Ref(id=collections)), 'ts': 1650393153190000, 'history_days': 30, 'name': 'weather_users'}]
[map[history_days:30 name:weather_reports ref:{weather_reports 0x140002844b0 0x140002844b0 <nil>} ts:1648443222280000] map[history_days:30 name:weather_users ref:{weather_users 0x140002845d0 0x140002845d0 <nil>} ts:1648443222280000]]
Arr(ObjectV(ref: RefV(id = "weather_reports", collection = RefV(id = "collections")),ts: LongV(1648443114870000),history_days: LongV(30),name: StringV(weather_reports)), ObjectV(ref: RefV(id = "weather_users", collection = RefV(id = "collections")),ts: LongV(1648443114870000),history_days: LongV(30),name: StringV(weather_users)))
[{ref: ref(id = "weather_reports", collection = ref(id = "collections")), ts: 1648443245900000, history_days: 30, name: "weather_reports"}, {ref: ref(id = "weather_users", collection = ref(id = "collections")), ts: 1648443245900000, history_days: 30, name: "weather_users"}]
[
{
ref: Collection("weather_reports"),
ts: 1648443426630000,
history_days: 30,
name: 'weather_reports'
},
{
ref: Collection("weather_users"),
ts: 1648443426630000,
history_days: 30,
name: 'weather_users'
}
]
Step 3: Create UDFs
We need three UDFs to perform the functions of this application. The
first one is called Get_weather_reports
, and it uses the
Documents
function to retrieve all the records in the
weather_reports
collection.
We haven’t created the required roles yet, so these UDFs
are created without the role definitions. Once the roles have
been created, we can update them to add the role definitions.
|
{
ref: Function("Get_weather_reports"),
ts: 1648443407730000,
name: 'Get_weather_reports',
body: Query(Lambda([], Map(Paginate(Documents(Collection("weather_reports"))), Lambda("report", Get(Var("report"))))))
}
{'ref': Ref(id=Get_weather_reports, collection=Ref(id=functions)), 'ts': 1650393154100000, 'name': 'Get_weather_reports', 'body': Query({'api_version': '4', 'lambda': [], 'expr': {'map': {'lambda': 'report', 'expr': {'get': {'var': 'report'}}}, 'collection': {'paginate': {'documents': {'collection': 'weather_reports'}}}}})}
map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 93 44 34 101 120 112 114 34 58 123 34 109 97 112 34 58 123 34 108 97 109 98 100 97 34 58 34 114 101 112 111 114 116 34 44 34 101 120 112 114 34 58 123 34 103 101 116 34 58 123 34 118 97 114 34 58 34 114 101 112 111 114 116 34 125 125 125 44 34 99 111 108 108 101 99 116 105 111 110 34 58 123 34 112 97 103 105 110 97 116 101 34 58 123 34 100 111 99 117 109 101 110 116 115 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 114 101 112 111 114 116 115 34 125 125 125 125 125]} name:Get_weather_reports ref:{Get_weather_reports 0x140002044b0 0x140002044b0 <nil>} ts:1648443223020000]
ObjectV(ref: RefV(id = "Get_weather_reports", collection = RefV(id = "functions")),ts: LongV(1648443122440000),name: StringV(Get_weather_reports),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]))
{ref: ref(id = "Get_weather_reports", collection = ref(id = "functions")), ts: 1648443257250000, name: "Get_weather_reports", body: QueryV({api_version=4, lambda=[], expr={map={lambda=report, expr={get={var=report}}}, collection={paginate={documents={collection=weather_reports}}}}})}
{
ref: Function("Get_weather_reports"),
ts: 1648443426910000,
name: 'Get_weather_reports',
body: Query(Lambda([], Map(Paginate(Documents(Collection("weather_reports"))), Lambda("report", Get(Var("report"))))))
}
The next function, Create_weather_report
, allows Reporters to create
new documents in the weather_reports
collection.
{
ref: Function("Create_weather_report"),
ts: 1648443407820000,
name: 'Create_weather_report',
body: Query(Lambda(["date", "city", "country", "temperature"], Create(Collection("weather_reports"), {"data": {"date": Var("date"), "city": Var("city"), "country": Var("country"), "temperature": Var("temperature")}})))
}
{'ref': Ref(id=Create_weather_report, collection=Ref(id=functions)), 'ts': 1650393155020000, 'name': 'Create_weather_report', 'body': Query({'api_version': '4', 'lambda': ['date', 'city', 'country', 'temperature'], 'expr': {'create': {'collection': 'weather_reports'}, 'params': {'object': {'data': {'object': {'date': {'var': 'date'}, 'city': {'var': 'city'}, 'countr': {'var': 'country'}, 'temperature': {'var': 'temperature'}}}}}}})}
map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 34 100 97 116 101 34 44 34 99 105 116 121 34 44 34 99 111 117 110 116 114 121 34 44 34 116 101 109 112 101 114 97 116 117 114 101 34 93 44 34 101 120 112 114 34 58 123 34 99 114 101 97 116 101 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 114 101 112 111 114 116 115 34 125 44 34 112 97 114 97 109 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 100 97 116 97 34 58 123 34 111 98 106 101 99 116 34 58 123 34 99 105 116 121 34 58 123 34 118 97 114 34 58 34 99 105 116 121 34 125 44 34 99 111 117 110 116 114 121 34 58 123 34 118 97 114 34 58 34 99 111 117 110 116 114 121 34 125 44 34 100 97 116 101 34 58 123 34 118 97 114 34 58 34 100 97 116 101 34 125 44 34 116 101 109 112 101 114 97 116 117 114 101 34 58 123 34 118 97 114 34 58 34 116 101 109 112 101 114 97 116 117 114 101 34 125 125 125 125 125 125 125]} name:Create_weather_report ref:{Create_weather_report 0x14000194240 0x14000194240 <nil>} ts:1648443223760000]
ObjectV(ref: RefV(id = "Create_weather_report", collection = RefV(id = "functions")),ts: LongV(1648443129880000),name: StringV(Create_weather_report),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]))
{ref: ref(id = "Create_weather_report", collection = ref(id = "functions")), ts: 1648443268590000, name: "Create_weather_report", body: QueryV({api_version=4, lambda=[date, city, country, temperature], expr={create={collection=weather_reports}, params={object={data={object={date={var=date}, city={var=city}, country={var=country}, temperature={var=temperature}}}}}}})}
{
ref: Function("Create_weather_report"),
ts: 1648443427200000,
name: 'Create_weather_report',
body: Query(Lambda(["date", "city", "country", "temperature"], Create(Collection("weather_reports"), {"data": {"date": Var("date"), "city": Var("city"), "country": Var("country"), "temperature": Var("temperature")}})))
}
The last UDF, Create_weather_user
, allows Managers to create new
documents in the weather_users
collection. Note that the password
field is passed via the credentials
parameter, which causes the
password string to be stored as a one-way cryptographic hash that is
subsequently used to authenticate the user. For more information, see
Credentials.
{
ref: Function("Create_weather_user"),
ts: 1648443407900000,
name: 'Create_weather_user',
body: Query(Lambda(["name", "email", "password"], Create(Collection("weather_users"), {"credentials": {"password": Var("password")}, "data": {"name": Var("name"), "email": Var("email")}})))
}
{'ref': Ref(id=Create_weather_user, collection=Ref(id=functions)), 'ts': 1650393155940000, 'name': 'Create_weather_user', 'body': Query({'api_version': '4', 'lambda': ['name', 'email', 'password'], 'expr': {'create': {'collection': 'weather_users'}, 'params': {'object': {'credentials': {'object': {'password': {'var': 'password'}}}, 'data': {'object': {'name': {'var': 'name'}, 'email': {'var': 'email'}}}}}}})}
map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 34 110 97 109 101 34 44 34 101 109 97 105 108 34 44 34 112 97 115 115 119 111 114 100 34 93 44 34 101 120 112 114 34 58 123 34 99 114 101 97 116 101 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 117 115 101 114 115 34 125 44 34 112 97 114 97 109 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 99 114 101 100 101 110 116 105 97 108 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 112 97 115 115 119 111 114 100 34 58 123 34 118 97 114 34 58 34 112 97 115 115 119 111 114 100 34 125 125 125 44 34 100 97 116 97 34 58 123 34 111 98 106 101 99 116 34 58 123 34 101 109 97 105 108 34 58 123 34 118 97 114 34 58 34 101 109 97 105 108 34 125 44 34 110 97 109 101 34 58 123 34 118 97 114 34 58 34 110 97 109 101 34 125 125 125 125 125 125 125]} name:Create_weather_user ref:{Create_weather_user 0x1400007bec0 0x1400007bec0 <nil>} ts:1648443224500000]
ObjectV(ref: RefV(id = "Create_weather_user", collection = RefV(id = "functions")),ts: LongV(1648443137530000),name: StringV(Create_weather_user),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]))
{ref: ref(id = "Create_weather_user", collection = ref(id = "functions")), ts: 1648443279870000, name: "Create_weather_user", body: QueryV({api_version=4, lambda=[name, email, password], expr={create={collection=weather_users}, params={object={credentials={object={password={var=password}}}, data={object={name={var=name}, email={var=email}}}}}}})}
{
ref: Function("Create_weather_user"),
ts: 1648443427490000,
name: 'Create_weather_user',
body: Query(Lambda(["name", "email", "password"], Create(Collection("weather_users"), {"credentials": {"password": Var("password")}, "data": {"email": Var("email"), "name": Var("name")}})))
}
Step 4: Create new user-defined roles
The next step is to create roles with narrowly-defined privileges to execute the UDFs.
First, create a new role called Reader
with the read
privilege on
the weather_reports
collection and the call
privilege on the
Get_weather_reports
function:
{
ref: Role("Reader"),
ts: 1648443407990000,
name: 'Reader',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
}
]
}
{'ref': Ref(id=Reader, collection=Ref(id=roles)), 'ts': 1650393156910000, 'name': 'Reader', 'privileges': [{'resource': Ref(id=weather_reports, collection=Ref(id=collections)), 'actions': {'read': True}}, {'resource': Ref(id=Get_weather_reports, collection=Ref(id=functions)), 'actions': {'call': True}}]}
map[name:Reader privileges:[map[actions:map[read:true] resource:{weather_reports 0x140001a6090 0x140001a6090 <nil>}] map[actions:map[call:true] resource:{Get_weather_reports 0x140001a61e0 0x140001a61e0 <nil>}]] ref:{Reader 0x14000115f20 0x14000115f20 <nil>} ts:1648443225240000]
ObjectV(ref: RefV(id = "Reader", collection = RefV(id = "roles")),ts: LongV(1648443144890000),name: StringV(Reader),privileges: Arr(ObjectV(resource: RefV(id = "weather_reports", collection = RefV(id = "collections")),actions: ObjectV(read: BooleanV(True))), ObjectV(resource: RefV(id = "Get_weather_reports", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True)))))
{ref: ref(id = "Reader", collection = ref(id = "roles")), ts: 1648443291270000, name: "Reader", privileges: [{resource: ref(id = "weather_reports", collection = ref(id = "collections")), actions: {read: true}}, {resource: ref(id = "Get_weather_reports", collection = ref(id = "functions")), actions: {call: true}}]}
{
ref: Role("Reader"),
ts: 1648443427780000,
name: 'Reader',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
}
]
}
Next, create a role named Reporter
. This role can create new documents
in weather_reports
, read from weather_reports
, and call the
Create_weather_report
and Get_weather_reports
functions.
{
ref: Role("Reporter"),
ts: 1648443408080000,
name: 'Reporter',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true, create: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
},
{
resource: Function("Create_weather_report"),
actions: { call: true }
}
]
}
{'ref': Ref(id=Reporter, collection=Ref(id=roles)), 'ts': 1650393157870000, 'name': 'Reporter', 'privileges': [{'resource': Ref(id=weather_reports, collection=Ref(id=collections)), 'actions': {'read': True, 'create': True}}, {'resource': Ref(id=Get_weather_reports, collection=Ref(id=functions)), 'actions': {'call': True}}, {'resource': Ref(id=Create_weather_report, collection=Ref(id=functions)), 'actions': {'call': True}}]}
map[name:Reporter privileges:[map[actions:map[create:true read:true] resource:{weather_reports 0x14000194390 0x14000194390 <nil>}] map[actions:map[call:true] resource:{Get_weather_reports 0x140001944e0 0x140001944e0 <nil>}] map[actions:map[call:true] resource:{Create_weather_report 0x14000194630 0x14000194630 <nil>}]] ref:{Reporter 0x14000194240 0x14000194240 <nil>} ts:1648443226010000]
ObjectV(ref: RefV(id = "Reporter", collection = RefV(id = "roles")),ts: LongV(1648443152520000),name: StringV(Reporter),privileges: Arr(ObjectV(resource: RefV(id = "weather_reports", collection = RefV(id = "collections")),actions: ObjectV(read: BooleanV(True),create: BooleanV(True))), ObjectV(resource: RefV(id = "Get_weather_reports", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True))), ObjectV(resource: RefV(id = "Create_weather_report", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True)))))
{ref: ref(id = "Reporter", collection = ref(id = "roles")), ts: 1648443302630000, name: "Reporter", privileges: [{resource: ref(id = "weather_reports", collection = ref(id = "collections")), actions: {read: true, create: true}}, {resource: ref(id = "Get_weather_reports", collection = ref(id = "functions")), actions: {call: true}}, {resource: ref(id = "Create_weather_report", collection = ref(id = "functions")), actions: {call: true}}]}
{
ref: Role("Reporter"),
ts: 1648443428070000,
name: 'Reporter',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true, create: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
},
{
resource: Function("Create_weather_report"),
actions: { call: true }
}
]
}
Lastly, create a role named Manager
. This role has read
and create
privileges on the weather_users
collection, read
privileges on
weather_reports
, and can call Create_weather_user
and
Get_weather_reports
.
{
ref: Role("Manager"),
ts: 1648443408170000,
name: 'Manager',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true }
},
{
resource: Collection("weather_users"),
actions: { read: true, create: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
},
{
resource: Function("Create_weather_report"),
actions: { call: true }
},
{
resource: Function("Create_weather_user"),
actions: { call: true }
}
]
}
{'ref': Ref(id=Manager, collection=Ref(id=roles)), 'ts': 1650393158840000, 'name': 'Manager', 'privileges': [{'resource': Ref(id=weather_reports, collection=Ref(id=collections)), 'actions': {'read': True}}, {'resource': Ref(id=weather_users, collection=Ref(id=collections)), 'actions': {'read': True, 'create': True}}, {'resource': Ref(id=Get_weather_reports, collection=Ref(id=functions)), 'actions': {'call': True}}, {'resource': Ref(id=Create_weather_report, collection=Ref(id=functions)), 'actions': {'call': True}}, {'resource': Ref(id=Create_weather_user, collection=Ref(id=functions)), 'actions': {'call': True}}]}
map[name:Manager privileges:[map[actions:map[read:true] resource:{weather_reports 0x140001703c0 0x140001703c0 <nil>}] map[actions:map[create:true read:true] resource:{weather_users 0x14000170510 0x14000170510 <nil>}] map[actions:map[read:true] resource:{Get_weather_reports 0x14000170660 0x14000170660 <nil>}] map[actions:map[read:true] resource:{Create_weather_report 0x140001707b0 0x140001707b0 <nil>}] map[actions:map[call:true] resource:{Create_weather_user 0x14000170900 0x14000170900 <nil>}]] ref:{Manager 0x14000170270 0x14000170270 <nil>} ts:1648443226760000]
ObjectV(ref: RefV(id = "Manager", collection = RefV(id = "roles")),ts: LongV(1648443160230000),name: StringV(Manager),privileges: Arr(ObjectV(resource: RefV(id = "weather_reports", collection = RefV(id = "collections")),actions: ObjectV(read: BooleanV(True))), ObjectV(resource: RefV(id = "weather_users", collection = RefV(id = "collections")),actions: ObjectV(read: BooleanV(True),create: BooleanV(True))), ObjectV(resource: RefV(id = "Get_weather_reports", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True))), ObjectV(resource: RefV(id = "Create_weather_report", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True))), ObjectV(resource: RefV(id = "Create_weather_user", collection = RefV(id = "functions")),actions: ObjectV(call: BooleanV(True)))))
{ref: ref(id = "Manager", collection = ref(id = "roles")), ts: 1648443314170000, name: "Manager", privileges: [{resource: ref(id = "weather_reports", collection = ref(id = "collections")), actions: {read: true}}, {resource: ref(id = "weather_users", collection = ref(id = "collections")), actions: {read: true, create: true}}, {resource: ref(id = "Get_weather_reports", collection = ref(id = "functions")), actions: {call: true}}, {resource: ref(id = "Create_weather_report", collection = ref(id = "functions")), actions: {call: true}}, {resource: ref(id = "Create_weather_user", collection = ref(id = "functions")), actions: {call: true}}]}
{
ref: Role("Manager"),
ts: 1648443428350000,
name: 'Manager',
privileges: [
{
resource: Collection("weather_reports"),
actions: { read: true }
},
{
resource: Collection("weather_users"),
actions: { read: true, create: true }
},
{
resource: Function("Get_weather_reports"),
actions: { call: true }
},
{
resource: Function("Create_weather_user"),
actions: { call: true }
}
]
}
Now your roles are all established, and you can assign them to the UDFs you created earlier.
Step 5: Assign roles to UDFs
Use the Update
function to update your UDFs to have associated
roles.
The following query:
-
Updates the
Get_weather_reports
function to have theReader
role. -
Updates the
Create_weather_report
function to have theReporter
role. -
Updates the
Create_weather_user
function to have theManager
role.
[
{
ref: Function("Get_weather_reports"),
ts: 1648443408270000,
name: 'Get_weather_reports',
body: Query(Lambda([], Map(Paginate(Documents(Collection("weather_reports"))), Lambda("report", Get(Var("report")))))),
role: Role("Reader")
},
{
ref: Function("Create_weather_report"),
ts: 1648443408270000,
name: 'Create_weather_report',
body: Query(Lambda(["date", "city", "country", "temperature"], Create(Collection("weather_reports"), {"data": {"date": Var("date"), "city": Var("city"), "country": Var("country"), "temperature": Var("temperature")}}))),
role: Role("Reporter")
},
{
ref: Function("Create_weather_user"),
ts: 1648443408270000,
name: 'Create_weather_user',
body: Query(Lambda(["name", "email", "password"], Create(Collection("weather_users"), {"credentials": {"password": Var("password")}, "data": {"name": Var("name"), "email": Var("email")}}))),
role: Role("Manager")
}
]
[{'ref': Ref(id=Get_weather_reports, collection=Ref(id=functions)), 'ts': 1650393159790000, 'name': 'Get_weather_reports', 'body': Query({'api_version': '4', 'lambda': [], 'expr': {'map': {'lambda': 'report', 'expr': {'get': {'var': 'report'}}}, 'collection': {'paginate': {'documents': {'collection': 'weather_reports'}}}}}), 'role': Ref(id=Reader, collection=Ref(id=roles))}, {'ref': Ref(id=Create_weather_report, collection=Ref(id=functions)), 'ts': 1650393159790000, 'name': 'Create_weather_report', 'body': Query({'api_version': '4', 'lambda': ['date', 'city', 'country', 'temperature'], 'expr': {'create': {'collection': 'weather_reports'}, 'params': {'object': {'data': {'object': {'date': {'var': 'date'}, 'city': {'var': 'city'}, 'countr': {'var': 'country'}, 'temperature': {'var': 'temperature'}}}}}}}), 'role': Ref(id=Reporter, collection=Ref(id=roles))}, {'ref': Ref(id=Create_weather_user, collection=Ref(id=functions)), 'ts': 1650393159790000, 'name': 'Create_weather_user', 'body': Query({'api_version': '4', 'lambda': ['name', 'email', 'password'], 'expr': {'create': {'collection': 'weather_users'}, 'params': {'object': {'credentials': {'object': {'password': {'var': 'password'}}}, 'data': {'object': {'name': {'var': 'name'}, 'email': {'var': 'email'}}}}}}}), 'role': Ref(id=Manager, collection=Ref(id=roles))}]
[map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 93 44 34 101 120 112 114 34 58 123 34 109 97 112 34 58 123 34 108 97 109 98 100 97 34 58 34 114 101 112 111 114 116 34 44 34 101 120 112 114 34 58 123 34 103 101 116 34 58 123 34 118 97 114 34 58 34 114 101 112 111 114 116 34 125 125 125 44 34 99 111 108 108 101 99 116 105 111 110 34 58 123 34 112 97 103 105 110 97 116 101 34 58 123 34 100 111 99 117 109 101 110 116 115 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 114 101 112 111 114 116 115 34 125 125 125 125 125]} name:Get_weather_reports ref:{Get_weather_reports 0x14000182240 0x14000182240 <nil>} role:{Reader 0x14000182330 0x14000182330 <nil>} ts:1648443227560000] map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 34 100 97 116 101 34 44 34 99 105 116 121 34 44 34 99 111 117 110 116 114 121 34 44 34 116 101 109 112 101 114 97 116 117 114 101 34 93 44 34 101 120 112 114 34 58 123 34 99 114 101 97 116 101 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 114 101 112 111 114 116 115 34 125 44 34 112 97 114 97 109 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 100 97 116 97 34 58 123 34 111 98 106 101 99 116 34 58 123 34 99 105 116 121 34 58 123 34 118 97 114 34 58 34 99 105 116 121 34 125 44 34 99 111 117 110 116 114 121 34 58 123 34 118 97 114 34 58 34 99 111 117 110 116 114 121 34 125 44 34 100 97 116 101 34 58 123 34 118 97 114 34 58 34 100 97 116 101 34 125 44 34 116 101 109 112 101 114 97 116 117 114 101 34 58 123 34 118 97 114 34 58 34 116 101 109 112 101 114 97 116 117 114 101 34 125 125 125 125 125 125 125]} name:Create_weather_report ref:{Create_weather_report 0x14000182450 0x14000182450 <nil>} role:{Reporter 0x14000182540 0x14000182540 <nil>} ts:1648443227560000] map[body:{[123 34 97 112 105 95 118 101 114 115 105 111 110 34 58 34 52 34 44 34 108 97 109 98 100 97 34 58 91 34 110 97 109 101 34 44 34 101 109 97 105 108 34 44 34 112 97 115 115 119 111 114 100 34 93 44 34 101 120 112 114 34 58 123 34 99 114 101 97 116 101 34 58 123 34 99 111 108 108 101 99 116 105 111 110 34 58 34 119 101 97 116 104 101 114 95 117 115 101 114 115 34 125 44 34 112 97 114 97 109 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 99 114 101 100 101 110 116 105 97 108 115 34 58 123 34 111 98 106 101 99 116 34 58 123 34 112 97 115 115 119 111 114 100 34 58 123 34 118 97 114 34 58 34 112 97 115 115 119 111 114 100 34 125 125 125 44 34 100 97 116 97 34 58 123 34 111 98 106 101 99 116 34 58 123 34 101 109 97 105 108 34 58 123 34 118 97 114 34 58 34 101 109 97 105 108 34 125 44 34 110 97 109 101 34 58 123 34 118 97 114 34 58 34 110 97 109 101 34 125 125 125 125 125 125 125]} name:Create_weather_user ref:{Create_weather_user 0x14000182660 0x14000182660 <nil>} role:{Manager 0x14000182750 0x14000182750 <nil>} ts:1648443227560000]]
Arr(ObjectV(ref: RefV(id = "Get_weather_reports", collection = RefV(id = "functions")),ts: LongV(1648443167610000),name: StringV(Get_weather_reports),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]),role: RefV(id = "Reader", collection = RefV(id = "roles"))), ObjectV(ref: RefV(id = "Create_weather_report", collection = RefV(id = "functions")),ts: LongV(1648443167610000),name: StringV(Create_weather_report),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]),role: RefV(id = "Reporter", collection = RefV(id = "roles"))), ObjectV(ref: RefV(id = "Create_weather_user", collection = RefV(id = "functions")),ts: LongV(1648443167610000),name: StringV(Create_weather_user),body: QueryV(System.Collections.Generic.Dictionary`2[System.String,FaunaDB.Query.Expr]),role: RefV(id = "Manager", collection = RefV(id = "roles"))))
[{ref: ref(id = "Get_weather_reports", collection = ref(id = "functions")), ts: 1648443325740000, name: "Get_weather_reports", body: QueryV({api_version=4, lambda=[], expr={map={lambda=report, expr={get={var=report}}}, collection={paginate={documents={collection=weather_reports}}}}}), role: ref(id = "Reader", collection = ref(id = "roles"))}, {ref: ref(id = "Create_weather_report", collection = ref(id = "functions")), ts: 1648443325740000, name: "Create_weather_report", body: QueryV({api_version=4, lambda=[date, city, country, temperature], expr={create={collection=weather_reports}, params={object={data={object={date={var=date}, city={var=city}, country={var=country}, temperature={var=temperature}}}}}}}), role: ref(id = "Reporter", collection = ref(id = "roles"))}, {ref: ref(id = "Create_weather_user", collection = ref(id = "functions")), ts: 1648443325740000, name: "Create_weather_user", body: QueryV({api_version=4, lambda=[name, email, password], expr={create={collection=weather_users}, params={object={credentials={object={password={var=password}}}, data={object={name={var=name}, email={var=email}}}}}}}), role: ref(id = "Manager", collection = ref(id = "roles"))}]
[
{
ref: Function("Get_weather_reports"),
ts: 1648443428630000,
name: 'Get_weather_reports',
body: Query(Lambda([], Map(Paginate(Documents(Collection("weather_reports"))), Lambda("report", Get(Var("report")))))),
role: Role("Reader")
},
{
ref: Function("Create_weather_report"),
ts: 1648443428630000,
name: 'Create_weather_report',
body: Query(Lambda(["date", "city", "country", "temperature"], Create(Collection("weather_reports"), {"data": {"date": Var("date"), "city": Var("city"), "country": Var("country"), "temperature": Var("temperature")}}))),
role: Role("Reporter")
},
{
ref: Function("Create_weather_user"),
ts: 1648443428630000,
name: 'Create_weather_user',
body: Query(Lambda(["name", "email", "password"], Create(Collection("weather_users"), {"credentials": {"password": Var("password")}, "data": {"email": Var("email"), "name": Var("name")}}))),
role: Role("Manager")
}
]
Step 6: Create API keys
If you are following along using the Dashboard Shell, you can skip ahead to Step 7: Create documents with the UDFs. |
Client applications which access your Fauna database with the secret from a key or a token. A secret is a password-equivalent that connects the application to a specific database using role-based privileges.
Each key that you create should be assigned a role with sufficient privileges to do its intended job, and no more. Tokens have no implicit privileges, and require creation of custom roles to grant privileges.
The following query creates three keys, having the roles we need for this example:
[
{
ref: Ref(Keys(), "327349235456410112"),
ts: 1648443408360000,
role: Role("Reader"),
secret: 'fnAEivplMOACAKHNeV3sp9pUdhP9nmfdPTZXWH1h',
hashed_secret: '$2a$05$AohJh7Ua5clOhKZovdB.duGilrGxbp/aoObITcyZ5kWtJeEpe4K72'
},
{
ref: Ref(Keys(), "327349235456411136"),
ts: 1648443408360000,
role: Role("Reporter"),
secret: 'fnAEivplMOAGAJlL_c2sU2tYOAjLDtwvjlOV7GM8',
hashed_secret: '$2a$05$yXeH6zRO9b.k/dEduiYK2eBHLPZ0y5e/41fTPT5JTOy8wVKIZCstm'
},
{
ref: Ref(Keys(), "327349235456412160"),
ts: 1648443408360000,
role: Role("Manager"),
secret: 'fnAEivplMOAKAPYFCqxcsC58_ebtJ_KminGgC9f1',
hashed_secret: '$2a$05$1BJbh7l1IqjgFcwhd4dqdu7YP6tiw4ujVmjv7skGrDNAk8Z/vyFN2'
}
]
[{'ref': Ref(id=329393699011166720, collection=Ref(id=keys)), 'ts': 1650393160750000, 'role': Ref(id=Reader, collection=Ref(id=roles)), 'secret': 'fnAEkj3S9NACAHbH-9RtYhorGj2Hz7x8fDjEVkF1', 'hashed_secret': '$2a$05$T7JjOxbVvWQY.ztf2dIphuAdDy.6.C4nogXJM3ehlqD41WButk8HK'}, {'ref': Ref(id=329393699011167744, collection=Ref(id=keys)), 'ts': 1650393160750000, 'role': Ref(id=Reader, collection=Ref(id=roles)), 'secret': 'fnAEkj3S9NAGAM8LmmYzIVtrTtqe9-f0ggIc-8RB', 'hashed_secret': '$2a$05$1QN0lYoF36asyMJt.LTgbeqb4Ih4pOw0UpnACLfHwt3zyFraWe/1W'}, {'ref': Ref(id=329393699011168768, collection=Ref(id=keys)), 'ts': 1650393160750000, 'role': Ref(id=Manager, collection=Ref(id=roles)), 'secret': 'fnAEkj3S9NAKAEqtdkUMHU1QFAUhQmTGGSsm2ZiQ', 'hashed_secret': '$2a$05$xKYiSMbWo0nRVyaFdsY2Tum7jYeVDe9Q.peFFHOXBeakGwGNuG5x2'}]
[map[hashed_secret:$2a$05$NrfAh.7sKdyzg.xyUZzOuuf7aw5jkpsHsDcxCGtmszs2tJkLYBfj6 ref:{327349046662398464 0x140000964b0 0x140000964b0 <nil>} role:{Reader 0x140000965a0 0x140000965a0 <nil>} secret:fnAEivo5O-ACAKn8PuQjO6wKXT6NQDfyjQ_iw8uh ts:1648443228310000] map[hashed_secret:$2a$05$LMztJ7WTEGFy.PUKBOxeF.YkmgSqSV.N8XgjfHImCxdOZV39BgiFG ref:{327349046662399488 0x140000966c0 0x140000966c0 <nil>} role:{Reporter 0x140000967b0 0x140000967b0 <nil>} secret:fnAEivo5O-AGACLnWko4jtVFNzWt_k3DPgZyFG81 ts:1648443228310000] map[hashed_secret:$2a$05$o61DDIbNMbG5rY6qwO34aOQnzhTKzO3ut9QKlJzNaxFIvXBZdoba. ref:{327349046662400512 0x140000968d0 0x140000968d0 <nil>} role:{Manager 0x140000969c0 0x140000969c0 <nil>} secret:fnAEivo5O-AKAM9QAOXF84X8AEGA2K6qCtzsNlxT ts:1648443228310000]]
Arr(ObjectV(ref: RefV(id = "327348990760714752", collection = RefV(id = "keys")),ts: LongV(1648443175000000),role: RefV(id = "Reader", collection = RefV(id = "roles")),secret: StringV(fnAEivosN-ACANgL7PSGqx3mT7z-DUB9tfd3SzkS),hashed_secret: StringV($2a$05$iajWOHPtAPkgtM4O2V6nA.w.ldSvcSN2nSapQPfkjYzwG.YLE9Rwu)), ObjectV(ref: RefV(id = "327348990760715776", collection = RefV(id = "keys")),ts: LongV(1648443175000000),role: RefV(id = "Reporter", collection = RefV(id = "roles")),secret: StringV(fnAEivosN-AGAKKvjNw4zvdtyaM-5nL_qY-BCvXl),hashed_secret: StringV($2a$05$/hPakXnawaCDarKjV84hyeLU1RWJvQsmcrvyBNr3U.e2GPJVP6J6O)), ObjectV(ref: RefV(id = "327348990760716800", collection = RefV(id = "keys")),ts: LongV(1648443175000000),role: RefV(id = "Manager", collection = RefV(id = "roles")),secret: StringV(fnAEivosN-AKAD5rbRkfykhcHqFXVCa3BiU4Ok9X),hashed_secret: StringV($2a$05$NArb7c0ZhAwOTb3p6DNPx.bTWbwVTrFLluy7NXh9g4Gz9aj8.uARq)))
[{ref: ref(id = "327349161105031680", collection = ref(id = "keys")), ts: 1648443337450000, role: ref(id = "Reader", collection = ref(id = "roles")), secret: "fnAEivpT4TACALJhk0Nx9W62s7TqMkaJD6kgoN6I", hashed_secret: "$2a$05$sYRiNIfd8NmOluHomYLeMO7nyrz8dT3uxto.dZF4UFAJkT1m8XbJi"}, {ref: ref(id = "327349161105032704", collection = ref(id = "keys")), ts: 1648443337450000, role: ref(id = "Reporter", collection = ref(id = "roles")), secret: "fnAEivpT4TAGADa0AoUQdRmVucrmnjw_GW2cdAy4", hashed_secret: "$2a$05$NCma3EpAM6IbN7TgyuR2vOrEDb5AR9dujWe4LD7qkJfjthhKJl7Cy"}, {ref: ref(id = "327349161105033728", collection = ref(id = "keys")), ts: 1648443337450000, role: ref(id = "Manager", collection = ref(id = "roles")), secret: "fnAEivpT4TAKABVBQCPxHv7Deccpwb36YLzgMLga", hashed_secret: "$2a$05$xy/ojeRFaKOZpKt0OCgLKOn3Bs4w8/EpBKaAsoz6LZuzDXpQAURWG"}]
[
{
ref: Ref(Keys(), "327349257024569856"),
ts: 1648443428920000,
role: Role("Reader"),
secret: 'fnAEivpqNnACAEYLR13MyfbKJCtIE89XzF-uVouT',
hashed_secret: '$2a$05$92XljLnZx617a.1OtwGOM.qiDvCqlX9rBPCsvKCchDgs2SUblJXhO'
},
{
ref: Ref(Keys(), "327349257024570880"),
ts: 1648443428920000,
role: Role("Reporter"),
secret: 'fnAEivpqNnAGANdBiR5wMXWfDA7srJboP56W9BJ3',
hashed_secret: '$2a$05$7h8izslky8S2R7J5k4GkwO2nQy60YjABf/ZZQGV.xd9mPx3AtEyDG'
},
{
ref: Ref(Keys(), "327349257024571904"),
ts: 1648443428920000,
role: Role("Manager"),
secret: 'fnAEivpqNnAKAKvpBgWBqozEZ-MUmtysS2ds8Qzi',
hashed_secret: '$2a$05$IC5MLu9d.shgWt0Mzfe/5uJ5u1myYtj4qUhMI5mFaf.BRtiMqE1I.'
}
]
A key’s secret is only displayed once, so be sure to save it in a safe place. |
If you’d like to do the same in the Fauna Dashboard:
-
Click the SECURITY link in the left-side navigation.
-
Click the NEW KEY link.
-
Select an appropriate role from the ROLE dropdown menu.
-
Give the key a name which describes its intended function.
-
Click SAVE.
Step 7: Create documents with the UDFs
So far, neither of the two collections have any documents. Now you can use your UDFs to add some documents.
Create a weather user document
In the Dashboard
-
Click SHELL in the left-side navigation.
-
Click the RUN AS button near the bottom of the screen. Select
Manager
from the dropdown menu. -
Enter the following query and click the RUN QUERY AS button:
{ ref: Ref(Collection("weather_users"), "327349258408690176"), ts: 1648443430240000, data: { email: 'alice@example.com', name: 'Alice Smith' } }
Note that if you change the RUN AS dropdown menu to Reader
and
run the query again it fails, because the Reader
role does not have
the necessary privilege to run the Create_weather_user
UDF.
Using a driver
{
ref: Ref(Collection("weather_users"), "327349236387545600"),
ts: 1648443409240000,
data: { name: 'Alice Smith', email: 'alice@example.com' }
}
{'ref': Ref(id=329393701651481088, collection=Ref(id=weather_users, collection=Ref(id=collections))), 'ts': 1650393163260000, 'data': {'name': 'Alice Smith', 'email': 'alice@example.com'}}
map[data:map[email:alice@example.com name:Alice Smith] ref:{327349048923128320 0x1400009c300 0x1400009c300 <nil>} ts:1648443230460000]
ObjectV(ref: RefV(id = "327349007072363008", collection = RefV(id = "weather_users", collection = RefV(id = "collections"))),ts: LongV(1648443190550000),data: ObjectV(name: StringV(Alice Smith),email: StringV(alice@example.com)))
{ref: ref(id = "327349185564115456", collection = ref(id = "weather_users", collection = ref(id = "collections"))), ts: 1648443360770000, data: {name: "Alice Smith", email: "alice@example.com"}}
{
ref: Ref(Collection("weather_users"), "327349258408690176"),
ts: 1648443430240000,
data: { email: 'alice@example.com', name: 'Alice Smith' }
}
Create a weather report
In the Dashboard
-
If the Shell screen is not in view, click SHELL in the left-side navigation.
-
Change the RUN AS dropdown menu to
Reporter
and run the following query:{ ref: Ref(Collection("weather_reports"), "327349259058807296"), ts: 1648443430860000, data: { date: '2022-02-24', city: 'Paris', country: 'France', temperature: '42 degrees F' } }
Using a driver
{
ref: Ref(Collection("weather_reports"), "327349236618232320"),
ts: 1648443409460000,
data: {
date: '2022-02-24',
city: 'Paris',
country: 'France',
temperature: '42 degrees F'
}
}
{'ref': Ref(id=329393703663698432, collection=Ref(id=weather_reports, collection=Ref(id=collections))), 'ts': 1650393165170000, 'data': {'date': '2022-02-24', 'city': 'Paris', 'countr': 'France', 'temperature': '42 degrees F'}}
map[data:map[city:Paris country:France date:2022-02-24 temperature:42 degrees F] ref:{327349050505429504 0x14000115b60 0x14000115b60 <nil>} ts:1648443231970000]
ObjectV(ref: RefV(id = "327349022696145408", collection = RefV(id = "weather_reports", collection = RefV(id = "collections"))),ts: LongV(1648443205450000),data: ObjectV(date: StringV(2022-02-24),city: StringV(Paris),country: StringV(France),temperature: StringV(42 degrees F)))
{ref: ref(id = "327349209323799040", collection = ref(id = "weather_reports", collection = ref(id = "collections"))), ts: 1648443383430000, data: {date: "2022-02-24", city: "Paris", country: "France", temperature: "42 degrees F"}}
{
ref: Ref(Collection("weather_reports"), "327349259058807296"),
ts: 1648443430860000,
data: {
date: '2022-02-24',
city: 'Paris',
country: 'France',
temperature: '42 degrees F'
}
}
Step 8: Fetch existing weather reports
In the Dashboard
-
If the Shell screen is not in view, click SHELL in the left-side navigation.
-
Change the RUN AS dropdown menu to
Reader
and run the following query:{ data: [ { ref: Ref(Collection("weather_reports"), "339108339609764352"), ts: 1659657763970000, data: { date: '2022-02-24', city: 'Paris', country: 'France', temperature: '42 degrees F' } } ] }
{'data': [{'ref': Ref(id=329393703663698432, collection=Ref(id=weather_reports, collection=Ref(id=collections))), 'ts': 1650393165170000, 'data': {'date': '2022-02-24', 'city': 'Paris', 'countr': 'France', 'temperature': '42 degrees F'}}]}
map[data:[map[data:map[city:Paris country:France date:2022-02-24 temperature:42 degrees F] ref:{327349050505429504 0x1400007b800 0x1400007b800 <nil>} ts:1648443231970000]]]
ObjectV(data: Arr(ObjectV(ref: RefV(id = "327349022696145408", collection = RefV(id = "weather_reports", collection = RefV(id = "collections"))),ts: LongV(1648443205450000),data: ObjectV(date: StringV(2022-02-24),city: StringV(Paris),country: StringV(France),temperature: StringV(42 degrees F)))))
{data: [{ref: ref(id = "327349209323799040", collection = ref(id = "weather_reports", collection = ref(id = "collections"))), ts: 1648443383430000, data: {date: "2022-02-24", city: "Paris", country: "France", temperature: "42 degrees F"}}]}
{ data: [ { ref: Ref(Collection("weather_reports"), "327349259058807296"), ts: 1648443430860000, data: { date: '2022-02-24', city: 'Paris', country: 'France', temperature: '42 degrees F' } } ] }
You can also run this query as either of the other roles, because they
all have the Call
privilege for it.
Using a driver
{
data: [
{
ref: Ref(Collection("weather_reports"), "339108339609764352"),
ts: 1659657763970000,
data: {
date: '2022-02-24',
city: 'Paris',
country: 'France',
temperature: '42 degrees F'
}
}
]
}
{'data': [{'ref': Ref(id=329393703663698432, collection=Ref(id=weather_reports, collection=Ref(id=collections))), 'ts': 1650393165170000, 'data': {'date': '2022-02-24', 'city': 'Paris', 'countr': 'France', 'temperature': '42 degrees F'}}]}
map[data:[map[data:map[city:Paris country:France date:2022-02-24 temperature:42 degrees F] ref:{327349050505429504 0x1400007b800 0x1400007b800 <nil>} ts:1648443231970000]]]
ObjectV(data: Arr(ObjectV(ref: RefV(id = "327349022696145408", collection = RefV(id = "weather_reports", collection = RefV(id = "collections"))),ts: LongV(1648443205450000),data: ObjectV(date: StringV(2022-02-24),city: StringV(Paris),country: StringV(France),temperature: StringV(42 degrees F)))))
{data: [{ref: ref(id = "327349209323799040", collection = ref(id = "weather_reports", collection = ref(id = "collections"))), ts: 1648443383430000, data: {date: "2022-02-24", city: "Paris", country: "France", temperature: "42 degrees F"}}]}
{
data: [
{
ref: Ref(Collection("weather_reports"), "327349259058807296"),
ts: 1648443430860000,
data: {
date: '2022-02-24',
city: 'Paris',
country: 'France',
temperature: '42 degrees F'
}
}
]
}
Is this article helpful?
Tell Fauna how the article can be improved:
Visit Fauna's forums
or email docs@fauna.com
Thank you for your feedback!