Security Rules
Security Rules in Oracle Backend with Firebase APIs define access control for database documents, collections, and storage objects. They determine who can access what data, under what conditions, and which operations are permitted. Rules are written in a declarative format using CEL (Common Expression Language) and are evaluated at runtime for every read or write request. These rules are essential for protecting sensitive data and enforcing business logic.
Note: When a JavaScript application is offline, supported writes can appear in its local view before the backend evaluates Security Rules. If the backend rejects a queued write, the SDK rolls back its local effect.
This chapter explains the structure, syntax, variables, and best practices for writing security rules for documents, collections, joins, and storage.
Rule Structure
Each rule is defined using the following structure:
match <path> {
allow <methods>: if <condition>;
}
| Component | Description |
|---|---|
match |
Specifies the document or collection path the rule applies to. |
allow |
Defines the permitted operations: get, list, create, update, delete. |
if |
A conditional expression that must evaluate to true for access to be granted. |
Supported Methods
| Component | Description |
|---|---|
get |
Read a single document |
list |
Query multiple documents |
read |
Applies to both single document reads and collection reads. Used only when get or list is not explicitly defined. |
create |
Add a new document |
update |
Modify an existing document |
write |
Applies to all write operations (create, update, delete). Used only when no specific write methods are defined. |
delete |
Remove a document |
Fixed Variables
Oracle Backend with Firebase APIs provides the following built-in variables to use in rule conditions:
request
request represents the incoming request from the client and has the following properties:
-
request.auth: Authentication context (such as, user ID-uid,email,displayName) -
request.resource.data: Data being written or updated -
request.time: ISO 8601 UTC Timestamp of the request -
request.method: Operation type ( such asget,list,create) -
request.path: Full path of the document or collection (For example,/user/user123/recipes) -
request.path_arr: Path as array (For example,["user","user123","recipes"])
resource
resource represents the existing document in the database and has the following property:
resource.data: Current document data, which is used for read operations and conditional updates
auth
auth is the shortcut for request.auth.
time
time is the shortcut for request.time.
Operators and Functions
Security rules support the following set of operators and CEL functions:
Table 21-1 Operators
| Operator | Description |
|---|---|
==, != |
Equality and inequality |
>, <, >=, <= |
Comparison |
&&, ` |
Logical operations |
-, /, %, * |
Math operations |
in, is |
Membership and type checks |
a[i], a.f |
Index and field access |
CEL Functions
Oracle Backend with Firebase APIs supports CEL functions for strings, lists, math, and timestamps.
Table 21-2 String Functions
| Operator | Example |
|---|---|
lower() |
'Burger'.lower() == 'burger' |
upper() |
'Burger'.upper() == 'BURGER' |
matches() |
'Chocolate Chip'.matches('.*Chip') == true |
replace() |
'ChocolateChip'.replace("Chip","Coco") == 'ChocolateCoco' |
size() |
'ChocolateChip'.size() == 13 |
split() |
'A,B,C'.split(',') == ['A','B','C'] |
trim() |
' A B '.trim() == 'AB' |
Table 21-3 List Functions
| Operator | Example |
|---|---|
concat() |
['A'].concat(['B']) == ['A','B'] |
hasAll() |
['A','B'].hasAll(['A']) == true |
hasAny() |
['A','B'].hasAny(['C','B']) == true |
hasOnly() |
['A','B'].hasOnly(['A','B','C']) == true |
size() |
['A','B'].size() == 2 |
Table 21-4 Math Functions
| Operator | Example |
|---|---|
abs() |
abs(-5) == 5 |
ceil() |
ceil(4.2) == 5 |
floor() |
floor(4.8) == 4 |
pow() |
pow(2,3) == 8 |
round() |
round(4.6) == 5 |
sqrt() |
sqrt(9) == 3 |
Table 21-5 Timestamp Functions
| Operator | Example |
|---|---|
year() |
request.time.year() == 2025 |
month() |
request.time.month() == 11 |
day() |
request.time.day() == 8 |
dayOfWeek() |
request.time.dayOfWeek() == 1..7 |
dayOfYear() |
request.time.dayOfYear() |
hours() |
request.time.hours() == 14 |
minutes() |
request.time.minutes() == 30 |
seconds() |
request.time.seconds() == 15 |
nanos() |
request.time.nanos() == 0 |
toMillis() |
request.time.toMillis() |
Example 21-1
allow update: if request.auth != null &&
request.auth.uid == resource.data.ownerId &&
request.time.year() == 2025;
Wildcard Rules
Wildcards allow rules to apply to multiple documents or collections using variable placeholders. Wildcards can be used in both path matching and condition logic.
match /users/{userId}/recipes/{recipeId} {
allow update: if request.auth.uid == userId;
}
Macros and Functions
Oracle Backend with Firebase APIs supports macros like exists() and get() to reference other documents in rules.
allow create: if exists(/users/$(request.resource.data.ownerId));
Using exists()
exists(path) returns true if the document at the given path exists.
allow create: if exists(/users/$(request.resource.data.ownerId));
get()
get(path) returns the document object at the given path.
allow get: if get(/projects/$(projectId)).data.status == "active";
Rule Examples
Example 21-2 Owner-Based Update
match /users/{userId}/recipes/{recipeId} {
allow update: if request.auth.uid == resource.data.uuid;
}
Example 21-3 Public Read with Fallback to Owner
match /posts/{postId} {
allow get: if resource.data.isPublic == true ||
request.auth.uid == resource.data.ownerId;
}
Example 21-4 Restrict Creation Based on Field
match /posts/{postId} {
allow create: if request.resource.data.isPublic == true;
}
Example 21-5 List Only Public Documents
match /posts/{postId} {
allow list: if request.auth != null &&
resource.data.isPublic == true;
}
Collection Group and Join Collection Rules
Collection Group Rules
Collection Group queries require rules that match the subcollection path and define access conditions.
match /users/{userId}/recipes/{recipeId}/notes/{noteId} {
allow list: if request.auth != null;
}
Join Collection Rules
Join queries must be backed by rules that match the join path and validate access.
match /EMP_DEP/_docId {
allow get: if request.auth != null;
}
Best Practices
-
Always define rules before deploying queries.
-
Use wildcards to generalize access control.
-
Validate both
requestandresourcefor write operations. -
Use macros like
exists()to enforce relational integrity. -
Keep rules readable and modular.